GDB (API)
|
00001 /* TUI display source/assembly window. 00002 00003 Copyright (C) 1998-2013 Free Software Foundation, Inc. 00004 00005 Contributed by Hewlett-Packard Company. 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00021 00022 #include "defs.h" 00023 #include <ctype.h> 00024 #include "symtab.h" 00025 #include "frame.h" 00026 #include "breakpoint.h" 00027 #include "value.h" 00028 #include "source.h" 00029 #include "objfiles.h" 00030 #include "filenames.h" 00031 00032 #include "tui/tui.h" 00033 #include "tui/tui-data.h" 00034 #include "tui/tui-stack.h" 00035 #include "tui/tui-win.h" 00036 #include "tui/tui-wingeneral.h" 00037 #include "tui/tui-winsource.h" 00038 #include "tui/tui-source.h" 00039 #include "tui/tui-disasm.h" 00040 00041 #include "gdb_string.h" 00042 #include "gdb_curses.h" 00043 #include "gdb_assert.h" 00044 00045 /* Function to display the "main" routine. */ 00046 void 00047 tui_display_main (void) 00048 { 00049 if ((tui_source_windows ())->count > 0) 00050 { 00051 struct gdbarch *gdbarch; 00052 CORE_ADDR addr; 00053 00054 tui_get_begin_asm_address (&gdbarch, &addr); 00055 if (addr != (CORE_ADDR) 0) 00056 { 00057 struct symtab_and_line sal; 00058 00059 tui_update_source_windows_with_addr (gdbarch, addr); 00060 sal = find_pc_line (addr, 0); 00061 if (sal.symtab) 00062 tui_update_locator_fullname (symtab_to_fullname (sal.symtab)); 00063 else 00064 tui_update_locator_fullname ("??"); 00065 } 00066 } 00067 } 00068 00069 00070 00071 /* Function to display source in the source window. This function 00072 initializes the horizontal scroll to 0. */ 00073 void 00074 tui_update_source_window (struct tui_win_info *win_info, 00075 struct gdbarch *gdbarch, 00076 struct symtab *s, 00077 struct tui_line_or_address line_or_addr, 00078 int noerror) 00079 { 00080 win_info->detail.source_info.horizontal_offset = 0; 00081 tui_update_source_window_as_is (win_info, gdbarch, s, line_or_addr, noerror); 00082 00083 return; 00084 } 00085 00086 00087 /* Function to display source in the source/asm window. This function 00088 shows the source as specified by the horizontal offset. */ 00089 void 00090 tui_update_source_window_as_is (struct tui_win_info *win_info, 00091 struct gdbarch *gdbarch, 00092 struct symtab *s, 00093 struct tui_line_or_address line_or_addr, 00094 int noerror) 00095 { 00096 enum tui_status ret; 00097 00098 if (win_info->generic.type == SRC_WIN) 00099 ret = tui_set_source_content (s, line_or_addr.u.line_no, noerror); 00100 else 00101 ret = tui_set_disassem_content (gdbarch, line_or_addr.u.addr); 00102 00103 if (ret == TUI_FAILURE) 00104 { 00105 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT); 00106 tui_clear_exec_info_content (win_info); 00107 } 00108 else 00109 { 00110 tui_update_breakpoint_info (win_info, 0); 00111 tui_show_source_content (win_info); 00112 tui_update_exec_info (win_info); 00113 if (win_info->generic.type == SRC_WIN) 00114 { 00115 struct symtab_and_line sal; 00116 00117 init_sal (&sal); 00118 sal.line = line_or_addr.u.line_no + 00119 (win_info->generic.content_size - 2); 00120 sal.symtab = s; 00121 sal.pspace = s->objfile->pspace; 00122 set_current_source_symtab_and_line (&sal); 00123 /* If the focus was in the asm win, put it in the src win if 00124 we don't have a split layout. */ 00125 if (tui_win_with_focus () == TUI_DISASM_WIN 00126 && tui_current_layout () != SRC_DISASSEM_COMMAND) 00127 tui_set_win_focus_to (TUI_SRC_WIN); 00128 } 00129 } 00130 00131 00132 return; 00133 } 00134 00135 00136 /* Function to ensure that the source and/or disassemly windows 00137 reflect the input address. */ 00138 void 00139 tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr) 00140 { 00141 if (addr != 0) 00142 { 00143 struct symtab_and_line sal; 00144 struct tui_line_or_address l; 00145 00146 switch (tui_current_layout ()) 00147 { 00148 case DISASSEM_COMMAND: 00149 case DISASSEM_DATA_COMMAND: 00150 tui_show_disassem (gdbarch, addr); 00151 break; 00152 case SRC_DISASSEM_COMMAND: 00153 tui_show_disassem_and_update_source (gdbarch, addr); 00154 break; 00155 default: 00156 sal = find_pc_line (addr, 0); 00157 l.loa = LOA_LINE; 00158 l.u.line_no = sal.line; 00159 tui_show_symtab_source (gdbarch, sal.symtab, l, FALSE); 00160 break; 00161 } 00162 } 00163 else 00164 { 00165 int i; 00166 00167 for (i = 0; i < (tui_source_windows ())->count; i++) 00168 { 00169 struct tui_win_info *win_info = (tui_source_windows ())->list[i]; 00170 00171 tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT); 00172 tui_clear_exec_info_content (win_info); 00173 } 00174 } 00175 } 00176 00177 /* Function to ensure that the source and/or disassemly windows 00178 reflect the input address. */ 00179 void 00180 tui_update_source_windows_with_line (struct symtab *s, int line) 00181 { 00182 struct gdbarch *gdbarch; 00183 CORE_ADDR pc; 00184 struct tui_line_or_address l; 00185 00186 if (!s) 00187 return; 00188 00189 gdbarch = get_objfile_arch (s->objfile); 00190 00191 switch (tui_current_layout ()) 00192 { 00193 case DISASSEM_COMMAND: 00194 case DISASSEM_DATA_COMMAND: 00195 find_line_pc (s, line, &pc); 00196 tui_update_source_windows_with_addr (gdbarch, pc); 00197 break; 00198 default: 00199 l.loa = LOA_LINE; 00200 l.u.line_no = line; 00201 tui_show_symtab_source (gdbarch, s, l, FALSE); 00202 if (tui_current_layout () == SRC_DISASSEM_COMMAND) 00203 { 00204 find_line_pc (s, line, &pc); 00205 tui_show_disassem (gdbarch, pc); 00206 } 00207 break; 00208 } 00209 00210 return; 00211 } 00212 00213 void 00214 tui_clear_source_content (struct tui_win_info *win_info, 00215 int display_prompt) 00216 { 00217 if (win_info != NULL) 00218 { 00219 int i; 00220 00221 win_info->generic.content_in_use = FALSE; 00222 tui_erase_source_content (win_info, display_prompt); 00223 for (i = 0; i < win_info->generic.content_size; i++) 00224 { 00225 struct tui_win_element *element = 00226 (struct tui_win_element *) win_info->generic.content[i]; 00227 00228 element->which_element.source.has_break = FALSE; 00229 element->which_element.source.is_exec_point = FALSE; 00230 } 00231 } 00232 } 00233 00234 00235 void 00236 tui_erase_source_content (struct tui_win_info *win_info, 00237 int display_prompt) 00238 { 00239 int x_pos; 00240 int half_width = (win_info->generic.width - 2) / 2; 00241 00242 if (win_info->generic.handle != (WINDOW *) NULL) 00243 { 00244 werase (win_info->generic.handle); 00245 tui_check_and_display_highlight_if_needed (win_info); 00246 if (display_prompt == EMPTY_SOURCE_PROMPT) 00247 { 00248 char *no_src_str; 00249 00250 if (win_info->generic.type == SRC_WIN) 00251 no_src_str = NO_SRC_STRING; 00252 else 00253 no_src_str = NO_DISASSEM_STRING; 00254 if (strlen (no_src_str) >= half_width) 00255 x_pos = 1; 00256 else 00257 x_pos = half_width - strlen (no_src_str); 00258 mvwaddstr (win_info->generic.handle, 00259 (win_info->generic.height / 2), 00260 x_pos, 00261 no_src_str); 00262 00263 /* elz: Added this function call to set the real contents of 00264 the window to what is on the screen, so that later calls 00265 to refresh, do display the correct stuff, and not the old 00266 image. */ 00267 00268 tui_set_source_content_nil (win_info, no_src_str); 00269 } 00270 tui_refresh_win (&win_info->generic); 00271 } 00272 } 00273 00274 00275 /* Redraw the complete line of a source or disassembly window. */ 00276 static void 00277 tui_show_source_line (struct tui_win_info *win_info, int lineno) 00278 { 00279 struct tui_win_element *line; 00280 int x, y; 00281 00282 line = (struct tui_win_element *) win_info->generic.content[lineno - 1]; 00283 if (line->which_element.source.is_exec_point) 00284 wattron (win_info->generic.handle, A_STANDOUT); 00285 00286 mvwaddstr (win_info->generic.handle, lineno, 1, 00287 line->which_element.source.line); 00288 if (line->which_element.source.is_exec_point) 00289 wattroff (win_info->generic.handle, A_STANDOUT); 00290 00291 /* Clear to end of line but stop before the border. */ 00292 getyx (win_info->generic.handle, y, x); 00293 while (x + 1 < win_info->generic.width) 00294 { 00295 waddch (win_info->generic.handle, ' '); 00296 getyx (win_info->generic.handle, y, x); 00297 } 00298 } 00299 00300 void 00301 tui_show_source_content (struct tui_win_info *win_info) 00302 { 00303 if (win_info->generic.content_size > 0) 00304 { 00305 int lineno; 00306 00307 for (lineno = 1; lineno <= win_info->generic.content_size; lineno++) 00308 tui_show_source_line (win_info, lineno); 00309 } 00310 else 00311 tui_erase_source_content (win_info, TRUE); 00312 00313 tui_check_and_display_highlight_if_needed (win_info); 00314 tui_refresh_win (&win_info->generic); 00315 win_info->generic.content_in_use = TRUE; 00316 } 00317 00318 00319 /* Scroll the source forward or backward horizontally. */ 00320 void 00321 tui_horizontal_source_scroll (struct tui_win_info *win_info, 00322 enum tui_scroll_direction direction, 00323 int num_to_scroll) 00324 { 00325 if (win_info->generic.content != NULL) 00326 { 00327 struct gdbarch *gdbarch = win_info->detail.source_info.gdbarch; 00328 int offset; 00329 struct symtab *s = NULL; 00330 00331 if (win_info->generic.type == SRC_WIN) 00332 { 00333 struct symtab_and_line cursal 00334 = get_current_source_symtab_and_line (); 00335 00336 if (cursal.symtab == NULL) 00337 s = find_pc_symtab (get_frame_pc (get_selected_frame (NULL))); 00338 else 00339 s = cursal.symtab; 00340 } 00341 00342 if (direction == LEFT_SCROLL) 00343 offset = win_info->detail.source_info.horizontal_offset 00344 + num_to_scroll; 00345 else 00346 { 00347 offset = win_info->detail.source_info.horizontal_offset 00348 - num_to_scroll; 00349 if (offset < 0) 00350 offset = 0; 00351 } 00352 win_info->detail.source_info.horizontal_offset = offset; 00353 tui_update_source_window_as_is (win_info, gdbarch, s, 00354 ((struct tui_win_element *) 00355 win_info->generic.content[0])->which_element.source.line_or_addr, 00356 FALSE); 00357 } 00358 00359 return; 00360 } 00361 00362 00363 /* Set or clear the has_break flag in the line whose line is 00364 line_no. */ 00365 00366 void 00367 tui_set_is_exec_point_at (struct tui_line_or_address l, 00368 struct tui_win_info *win_info) 00369 { 00370 int changed = 0; 00371 int i; 00372 tui_win_content content = (tui_win_content) win_info->generic.content; 00373 00374 i = 0; 00375 while (i < win_info->generic.content_size) 00376 { 00377 int new_state; 00378 struct tui_line_or_address content_loa = 00379 content[i]->which_element.source.line_or_addr; 00380 00381 gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE); 00382 gdb_assert (content_loa.loa == LOA_LINE 00383 || content_loa.loa == LOA_ADDRESS); 00384 if (content_loa.loa == l.loa 00385 && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no) 00386 || (content_loa.u.addr == l.u.addr))) 00387 new_state = TRUE; 00388 else 00389 new_state = FALSE; 00390 if (new_state != content[i]->which_element.source.is_exec_point) 00391 { 00392 changed++; 00393 content[i]->which_element.source.is_exec_point = new_state; 00394 tui_show_source_line (win_info, i + 1); 00395 } 00396 i++; 00397 } 00398 if (changed) 00399 tui_refresh_win (&win_info->generic); 00400 } 00401 00402 /* Update the execution windows to show the active breakpoints. 00403 This is called whenever a breakpoint is inserted, removed or 00404 has its state changed. */ 00405 void 00406 tui_update_all_breakpoint_info (void) 00407 { 00408 struct tui_list *list = tui_source_windows (); 00409 int i; 00410 00411 for (i = 0; i < list->count; i++) 00412 { 00413 struct tui_win_info *win = list->list[i]; 00414 00415 if (tui_update_breakpoint_info (win, FALSE)) 00416 { 00417 tui_update_exec_info (win); 00418 } 00419 } 00420 } 00421 00422 00423 /* Scan the source window and the breakpoints to update the has_break 00424 information for each line. 00425 00426 Returns 1 if something changed and the execution window must be 00427 refreshed. */ 00428 00429 int 00430 tui_update_breakpoint_info (struct tui_win_info *win, 00431 int current_only) 00432 { 00433 int i; 00434 int need_refresh = 0; 00435 struct tui_source_info *src = &win->detail.source_info; 00436 00437 for (i = 0; i < win->generic.content_size; i++) 00438 { 00439 struct breakpoint *bp; 00440 extern struct breakpoint *breakpoint_chain; 00441 int mode; 00442 struct tui_source_element *line; 00443 00444 line = &((struct tui_win_element *) 00445 win->generic.content[i])->which_element.source; 00446 if (current_only && !line->is_exec_point) 00447 continue; 00448 00449 /* Scan each breakpoint to see if the current line has something to 00450 do with it. Identify enable/disabled breakpoints as well as 00451 those that we already hit. */ 00452 mode = 0; 00453 for (bp = breakpoint_chain; 00454 bp != (struct breakpoint *) NULL; 00455 bp = bp->next) 00456 { 00457 struct bp_location *loc; 00458 00459 gdb_assert (line->line_or_addr.loa == LOA_LINE 00460 || line->line_or_addr.loa == LOA_ADDRESS); 00461 00462 for (loc = bp->loc; loc != NULL; loc = loc->next) 00463 { 00464 if ((win == TUI_SRC_WIN 00465 && loc->symtab != NULL 00466 && filename_cmp (src->fullname, 00467 symtab_to_fullname (loc->symtab)) == 0 00468 && line->line_or_addr.loa == LOA_LINE 00469 && loc->line_number == line->line_or_addr.u.line_no) 00470 || (win == TUI_DISASM_WIN 00471 && line->line_or_addr.loa == LOA_ADDRESS 00472 && loc->address == line->line_or_addr.u.addr)) 00473 { 00474 if (bp->enable_state == bp_disabled) 00475 mode |= TUI_BP_DISABLED; 00476 else 00477 mode |= TUI_BP_ENABLED; 00478 if (bp->hit_count) 00479 mode |= TUI_BP_HIT; 00480 if (bp->loc->cond) 00481 mode |= TUI_BP_CONDITIONAL; 00482 if (bp->type == bp_hardware_breakpoint) 00483 mode |= TUI_BP_HARDWARE; 00484 } 00485 } 00486 } 00487 if (line->has_break != mode) 00488 { 00489 line->has_break = mode; 00490 need_refresh = 1; 00491 } 00492 } 00493 return need_refresh; 00494 } 00495 00496 00497 /* Function to initialize the content of the execution info window, 00498 based upon the input window which is either the source or 00499 disassembly window. */ 00500 enum tui_status 00501 tui_set_exec_info_content (struct tui_win_info *win_info) 00502 { 00503 enum tui_status ret = TUI_SUCCESS; 00504 00505 if (win_info->detail.source_info.execution_info 00506 != (struct tui_gen_win_info *) NULL) 00507 { 00508 struct tui_gen_win_info *exec_info_ptr 00509 = win_info->detail.source_info.execution_info; 00510 00511 if (exec_info_ptr->content == NULL) 00512 exec_info_ptr->content = 00513 (void **) tui_alloc_content (win_info->generic.height, 00514 exec_info_ptr->type); 00515 if (exec_info_ptr->content != NULL) 00516 { 00517 int i; 00518 00519 tui_update_breakpoint_info (win_info, 1); 00520 for (i = 0; i < win_info->generic.content_size; i++) 00521 { 00522 struct tui_win_element *element; 00523 struct tui_win_element *src_element; 00524 int mode; 00525 00526 element = (struct tui_win_element *) exec_info_ptr->content[i]; 00527 src_element = (struct tui_win_element *) 00528 win_info->generic.content[i]; 00529 00530 memset(element->which_element.simple_string, ' ', 00531 sizeof(element->which_element.simple_string)); 00532 element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0; 00533 00534 /* Now update the exec info content based upon the state 00535 of each line as indicated by the source content. */ 00536 mode = src_element->which_element.source.has_break; 00537 if (mode & TUI_BP_HIT) 00538 element->which_element.simple_string[TUI_BP_HIT_POS] = 00539 (mode & TUI_BP_HARDWARE) ? 'H' : 'B'; 00540 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED)) 00541 element->which_element.simple_string[TUI_BP_HIT_POS] = 00542 (mode & TUI_BP_HARDWARE) ? 'h' : 'b'; 00543 00544 if (mode & TUI_BP_ENABLED) 00545 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+'; 00546 else if (mode & TUI_BP_DISABLED) 00547 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-'; 00548 00549 if (src_element->which_element.source.is_exec_point) 00550 element->which_element.simple_string[TUI_EXEC_POS] = '>'; 00551 } 00552 exec_info_ptr->content_size = win_info->generic.content_size; 00553 } 00554 else 00555 ret = TUI_FAILURE; 00556 } 00557 00558 return ret; 00559 } 00560 00561 00562 void 00563 tui_show_exec_info_content (struct tui_win_info *win_info) 00564 { 00565 struct tui_gen_win_info *exec_info 00566 = win_info->detail.source_info.execution_info; 00567 int cur_line; 00568 00569 werase (exec_info->handle); 00570 tui_refresh_win (exec_info); 00571 for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++) 00572 mvwaddstr (exec_info->handle, 00573 cur_line, 00574 0, 00575 ((struct tui_win_element *) 00576 exec_info->content[cur_line - 1])->which_element.simple_string); 00577 tui_refresh_win (exec_info); 00578 exec_info->content_in_use = TRUE; 00579 } 00580 00581 00582 void 00583 tui_erase_exec_info_content (struct tui_win_info *win_info) 00584 { 00585 struct tui_gen_win_info *exec_info 00586 = win_info->detail.source_info.execution_info; 00587 00588 werase (exec_info->handle); 00589 tui_refresh_win (exec_info); 00590 } 00591 00592 void 00593 tui_clear_exec_info_content (struct tui_win_info *win_info) 00594 { 00595 win_info->detail.source_info.execution_info->content_in_use = FALSE; 00596 tui_erase_exec_info_content (win_info); 00597 00598 return; 00599 } 00600 00601 /* Function to update the execution info window. */ 00602 void 00603 tui_update_exec_info (struct tui_win_info *win_info) 00604 { 00605 tui_set_exec_info_content (win_info); 00606 tui_show_exec_info_content (win_info); 00607 } 00608 00609 enum tui_status 00610 tui_alloc_source_buffer (struct tui_win_info *win_info) 00611 { 00612 char *src_line_buf; 00613 int i, line_width, max_lines; 00614 00615 max_lines = win_info->generic.height; /* Less the highlight box. */ 00616 line_width = win_info->generic.width - 1; 00617 /* 00618 * Allocate the buffer for the source lines. Do this only once 00619 * since they will be re-used for all source displays. The only 00620 * other time this will be done is when a window's size changes. 00621 */ 00622 if (win_info->generic.content == NULL) 00623 { 00624 src_line_buf = (char *) 00625 xmalloc ((max_lines * line_width) * sizeof (char)); 00626 if (src_line_buf == (char *) NULL) 00627 { 00628 fputs_unfiltered ("Unable to Allocate Memory for " 00629 "Source or Disassembly Display.\n", 00630 gdb_stderr); 00631 return TUI_FAILURE; 00632 } 00633 /* Allocate the content list. */ 00634 if ((win_info->generic.content = 00635 (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL) 00636 { 00637 xfree (src_line_buf); 00638 fputs_unfiltered ("Unable to Allocate Memory for " 00639 "Source or Disassembly Display.\n", 00640 gdb_stderr); 00641 return TUI_FAILURE; 00642 } 00643 for (i = 0; i < max_lines; i++) 00644 ((struct tui_win_element *) 00645 win_info->generic.content[i])->which_element.source.line = 00646 src_line_buf + (line_width * i); 00647 } 00648 00649 return TUI_SUCCESS; 00650 } 00651 00652 00653 /* Answer whether a particular line number or address is displayed 00654 in the current source window. */ 00655 int 00656 tui_line_is_displayed (int line, 00657 struct tui_win_info *win_info, 00658 int check_threshold) 00659 { 00660 int is_displayed = FALSE; 00661 int i, threshold; 00662 00663 if (check_threshold) 00664 threshold = SCROLL_THRESHOLD; 00665 else 00666 threshold = 0; 00667 i = 0; 00668 while (i < win_info->generic.content_size - threshold 00669 && !is_displayed) 00670 { 00671 is_displayed = (((struct tui_win_element *) 00672 win_info->generic.content[i])->which_element.source.line_or_addr.loa 00673 == LOA_LINE) 00674 && (((struct tui_win_element *) 00675 win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no 00676 == (int) line); 00677 i++; 00678 } 00679 00680 return is_displayed; 00681 } 00682 00683 00684 /* Answer whether a particular line number or address is displayed 00685 in the current source window. */ 00686 int 00687 tui_addr_is_displayed (CORE_ADDR addr, 00688 struct tui_win_info *win_info, 00689 int check_threshold) 00690 { 00691 int is_displayed = FALSE; 00692 int i, threshold; 00693 00694 if (check_threshold) 00695 threshold = SCROLL_THRESHOLD; 00696 else 00697 threshold = 0; 00698 i = 0; 00699 while (i < win_info->generic.content_size - threshold 00700 && !is_displayed) 00701 { 00702 is_displayed = (((struct tui_win_element *) 00703 win_info->generic.content[i])->which_element.source.line_or_addr.loa 00704 == LOA_ADDRESS) 00705 && (((struct tui_win_element *) 00706 win_info->generic.content[i])->which_element.source.line_or_addr.u.addr 00707 == addr); 00708 i++; 00709 } 00710 00711 return is_displayed; 00712 } 00713 00714 00715 /***************************************** 00716 ** STATIC LOCAL FUNCTIONS ** 00717 ******************************************/