| /* TUI display source/assembly window. |
| |
| Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, |
| Inc. |
| |
| Contributed by Hewlett-Packard Company. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| /* FIXME: cagney/2002-02-28: The GDB coding standard indicates that |
| "defs.h" should be included first. Unfortunatly some systems |
| (currently Debian GNU/Linux) include the <stdbool.h> via <curses.h> |
| and they clash with "bfd.h"'s definiton of true/false. The correct |
| fix is to remove true/false from "bfd.h", however, until that |
| happens, hack around it by including "config.h" and <curses.h> |
| first. */ |
| |
| #include "config.h" |
| #ifdef HAVE_NCURSES_H |
| #include <ncurses.h> |
| #else |
| #ifdef HAVE_CURSES_H |
| #include <curses.h> |
| #endif |
| #endif |
| |
| #include "defs.h" |
| #include <ctype.h> |
| #include "symtab.h" |
| #include "frame.h" |
| #include "breakpoint.h" |
| #include "value.h" |
| #include "source.h" |
| |
| #include "tui.h" |
| #include "tuiData.h" |
| #include "tuiStack.h" |
| #include "tuiWin.h" |
| #include "tuiGeneralWin.h" |
| #include "tuiSourceWin.h" |
| #include "tuiSource.h" |
| #include "tuiDisassem.h" |
| |
| |
| /* Function to display the "main" routine. */ |
| void |
| tui_display_main (void) |
| { |
| if ((sourceWindows ())->count > 0) |
| { |
| CORE_ADDR addr; |
| |
| addr = tuiGetBeginAsmAddress (); |
| if (addr != (CORE_ADDR) 0) |
| { |
| struct symtab_and_line sal; |
| |
| tuiUpdateSourceWindowsWithAddr (addr); |
| sal = find_pc_line (addr, 0); |
| if (sal.symtab) |
| tuiUpdateLocatorFilename (sal.symtab->filename); |
| else |
| tuiUpdateLocatorFilename ("??"); |
| } |
| } |
| } |
| |
| |
| |
| /* |
| ** tuiUpdateSourceWindow(). |
| ** Function to display source in the source window. This function |
| ** initializes the horizontal scroll to 0. |
| */ |
| void |
| tuiUpdateSourceWindow (TuiWinInfoPtr winInfo, struct symtab *s, |
| TuiLineOrAddress lineOrAddr, int noerror) |
| { |
| winInfo->detail.sourceInfo.horizontalOffset = 0; |
| tuiUpdateSourceWindowAsIs (winInfo, s, lineOrAddr, noerror); |
| |
| return; |
| } /* tuiUpdateSourceWindow */ |
| |
| |
| /* |
| ** tuiUpdateSourceWindowAsIs(). |
| ** Function to display source in the source/asm window. This |
| ** function shows the source as specified by the horizontal offset. |
| */ |
| void |
| tuiUpdateSourceWindowAsIs (TuiWinInfoPtr winInfo, struct symtab *s, |
| TuiLineOrAddress lineOrAddr, int noerror) |
| { |
| TuiStatus ret; |
| |
| if (winInfo->generic.type == SRC_WIN) |
| ret = tuiSetSourceContent (s, lineOrAddr.lineNo, noerror); |
| else |
| ret = tuiSetDisassemContent (lineOrAddr.addr); |
| |
| if (ret == TUI_FAILURE) |
| { |
| tuiClearSourceContent (winInfo, EMPTY_SOURCE_PROMPT); |
| tuiClearExecInfoContent (winInfo); |
| } |
| else |
| { |
| tui_update_breakpoint_info (winInfo, 0); |
| tuiShowSourceContent (winInfo); |
| tuiUpdateExecInfo (winInfo); |
| if (winInfo->generic.type == SRC_WIN) |
| { |
| struct symtab_and_line sal; |
| |
| sal.line = lineOrAddr.lineNo + |
| (winInfo->generic.contentSize - 2); |
| sal.symtab = s; |
| set_current_source_symtab_and_line (&sal); |
| /* |
| ** If the focus was in the asm win, put it in the src |
| ** win if we don't have a split layout |
| */ |
| if (tuiWinWithFocus () == disassemWin && |
| currentLayout () != SRC_DISASSEM_COMMAND) |
| tuiSetWinFocusTo (srcWin); |
| } |
| } |
| |
| |
| return; |
| } /* tuiUpdateSourceWindowAsIs */ |
| |
| |
| /* |
| ** tuiUpdateSourceWindowsWithAddr(). |
| ** Function to ensure that the source and/or disassemly windows |
| ** reflect the input address. |
| */ |
| void |
| tuiUpdateSourceWindowsWithAddr (CORE_ADDR addr) |
| { |
| if (addr != 0) |
| { |
| struct symtab_and_line sal; |
| TuiLineOrAddress l; |
| |
| switch (currentLayout ()) |
| { |
| case DISASSEM_COMMAND: |
| case DISASSEM_DATA_COMMAND: |
| tuiShowDisassem (addr); |
| break; |
| case SRC_DISASSEM_COMMAND: |
| tuiShowDisassemAndUpdateSource (addr); |
| break; |
| default: |
| sal = find_pc_line (addr, 0); |
| l.lineNo = sal.line; |
| tuiShowSource (sal.symtab, l, FALSE); |
| break; |
| } |
| } |
| else |
| { |
| int i; |
| |
| for (i = 0; i < (sourceWindows ())->count; i++) |
| { |
| TuiWinInfoPtr winInfo = (TuiWinInfoPtr) (sourceWindows ())->list[i]; |
| |
| tuiClearSourceContent (winInfo, EMPTY_SOURCE_PROMPT); |
| tuiClearExecInfoContent (winInfo); |
| } |
| } |
| |
| return; |
| } /* tuiUpdateSourceWindowsWithAddr */ |
| |
| /* |
| ** tuiUpdateSourceWindowsWithLine(). |
| ** Function to ensure that the source and/or disassemly windows |
| ** reflect the input address. |
| */ |
| void |
| tuiUpdateSourceWindowsWithLine (struct symtab *s, int line) |
| { |
| CORE_ADDR pc; |
| TuiLineOrAddress l; |
| |
| switch (currentLayout ()) |
| { |
| case DISASSEM_COMMAND: |
| case DISASSEM_DATA_COMMAND: |
| find_line_pc (s, line, &pc); |
| tuiUpdateSourceWindowsWithAddr (pc); |
| break; |
| default: |
| l.lineNo = line; |
| tuiShowSource (s, l, FALSE); |
| if (currentLayout () == SRC_DISASSEM_COMMAND) |
| { |
| find_line_pc (s, line, &pc); |
| tuiShowDisassem (pc); |
| } |
| break; |
| } |
| |
| return; |
| } /* tuiUpdateSourceWindowsWithLine */ |
| |
| /* |
| ** tuiClearSourceContent(). |
| */ |
| void |
| tuiClearSourceContent (TuiWinInfoPtr winInfo, int displayPrompt) |
| { |
| if (m_winPtrNotNull (winInfo)) |
| { |
| register int i; |
| |
| winInfo->generic.contentInUse = FALSE; |
| tuiEraseSourceContent (winInfo, displayPrompt); |
| for (i = 0; i < winInfo->generic.contentSize; i++) |
| { |
| TuiWinElementPtr element = |
| (TuiWinElementPtr) winInfo->generic.content[i]; |
| element->whichElement.source.hasBreak = FALSE; |
| element->whichElement.source.isExecPoint = FALSE; |
| } |
| } |
| |
| return; |
| } /* tuiClearSourceContent */ |
| |
| |
| /* |
| ** tuiEraseSourceContent(). |
| */ |
| void |
| tuiEraseSourceContent (TuiWinInfoPtr winInfo, int displayPrompt) |
| { |
| int xPos; |
| int halfWidth = (winInfo->generic.width - 2) / 2; |
| |
| if (winInfo->generic.handle != (WINDOW *) NULL) |
| { |
| werase (winInfo->generic.handle); |
| checkAndDisplayHighlightIfNeeded (winInfo); |
| if (displayPrompt == EMPTY_SOURCE_PROMPT) |
| { |
| char *noSrcStr; |
| |
| if (winInfo->generic.type == SRC_WIN) |
| noSrcStr = NO_SRC_STRING; |
| else |
| noSrcStr = NO_DISASSEM_STRING; |
| if (strlen (noSrcStr) >= halfWidth) |
| xPos = 1; |
| else |
| xPos = halfWidth - strlen (noSrcStr); |
| mvwaddstr (winInfo->generic.handle, |
| (winInfo->generic.height / 2), |
| xPos, |
| noSrcStr); |
| |
| /* elz: added this function call to set the real contents of |
| the window to what is on the screen, so that later calls |
| to refresh, do display |
| the correct stuff, and not the old image */ |
| |
| tuiSetSourceContentNil (winInfo, noSrcStr); |
| } |
| tuiRefreshWin (&winInfo->generic); |
| } |
| return; |
| } /* tuiEraseSourceContent */ |
| |
| |
| /* Redraw the complete line of a source or disassembly window. */ |
| static void |
| tui_show_source_line (TuiWinInfoPtr winInfo, int lineno) |
| { |
| TuiWinElementPtr line; |
| int x, y; |
| |
| line = (TuiWinElementPtr) winInfo->generic.content[lineno - 1]; |
| if (line->whichElement.source.isExecPoint) |
| wattron (winInfo->generic.handle, A_STANDOUT); |
| |
| mvwaddstr (winInfo->generic.handle, lineno, 1, |
| line->whichElement.source.line); |
| if (line->whichElement.source.isExecPoint) |
| wattroff (winInfo->generic.handle, A_STANDOUT); |
| |
| /* Clear to end of line but stop before the border. */ |
| getyx (winInfo->generic.handle, y, x); |
| while (x + 1 < winInfo->generic.width) |
| { |
| waddch (winInfo->generic.handle, ' '); |
| getyx (winInfo->generic.handle, y, x); |
| } |
| } |
| |
| /* |
| ** tuiShowSourceContent(). |
| */ |
| void |
| tuiShowSourceContent (TuiWinInfoPtr winInfo) |
| { |
| if (winInfo->generic.contentSize > 0) |
| { |
| int lineno; |
| |
| for (lineno = 1; lineno <= winInfo->generic.contentSize; lineno++) |
| tui_show_source_line (winInfo, lineno); |
| } |
| else |
| tuiEraseSourceContent (winInfo, TRUE); |
| |
| checkAndDisplayHighlightIfNeeded (winInfo); |
| tuiRefreshWin (&winInfo->generic); |
| winInfo->generic.contentInUse = TRUE; |
| } |
| |
| |
| /* |
| ** tuiHorizontalSourceScroll(). |
| ** Scroll the source forward or backward horizontally |
| */ |
| void |
| tuiHorizontalSourceScroll (TuiWinInfoPtr winInfo, |
| TuiScrollDirection direction, |
| int numToScroll) |
| { |
| if (winInfo->generic.content != (OpaquePtr) NULL) |
| { |
| int offset; |
| struct symtab *s; |
| struct symtab_and_line cursal = get_current_source_symtab_and_line (); |
| |
| if (cursal.symtab == (struct symtab *) NULL) |
| s = find_pc_symtab (deprecated_selected_frame->pc); |
| else |
| s = cursal.symtab; |
| |
| if (direction == LEFT_SCROLL) |
| offset = winInfo->detail.sourceInfo.horizontalOffset + numToScroll; |
| else |
| { |
| if ((offset = |
| winInfo->detail.sourceInfo.horizontalOffset - numToScroll) < 0) |
| offset = 0; |
| } |
| winInfo->detail.sourceInfo.horizontalOffset = offset; |
| tuiUpdateSourceWindowAsIs ( |
| winInfo, |
| s, |
| ((TuiWinElementPtr) |
| winInfo->generic.content[0])->whichElement.source.lineOrAddr, |
| FALSE); |
| } |
| |
| return; |
| } /* tuiHorizontalSourceScroll */ |
| |
| |
| /* Set or clear the hasBreak flag in the line whose line is lineNo. */ |
| void |
| tuiSetIsExecPointAt (TuiLineOrAddress l, TuiWinInfoPtr winInfo) |
| { |
| int changed = 0; |
| int i; |
| TuiWinContent content = (TuiWinContent) winInfo->generic.content; |
| |
| i = 0; |
| while (i < winInfo->generic.contentSize) |
| { |
| int newState; |
| |
| if (content[i]->whichElement.source.lineOrAddr.addr == l.addr) |
| newState = TRUE; |
| else |
| newState = FALSE; |
| if (newState != content[i]->whichElement.source.isExecPoint) |
| { |
| changed++; |
| content[i]->whichElement.source.isExecPoint = newState; |
| tui_show_source_line (winInfo, i + 1); |
| } |
| i++; |
| } |
| if (changed) |
| tuiRefreshWin (&winInfo->generic); |
| } |
| |
| /* Update the execution windows to show the active breakpoints. |
| This is called whenever a breakpoint is inserted, removed or |
| has its state changed. */ |
| void |
| tui_update_all_breakpoint_info () |
| { |
| TuiList* list = sourceWindows (); |
| int i; |
| |
| for (i = 0; i < list->count; i++) |
| { |
| TuiWinInfoPtr win = (TuiWinInfoPtr) list->list[i]; |
| |
| if (tui_update_breakpoint_info (win, FALSE)) |
| { |
| tuiUpdateExecInfo (win); |
| } |
| } |
| } |
| |
| |
| /* Scan the source window and the breakpoints to update the |
| hasBreak information for each line. |
| Returns 1 if something changed and the execution window |
| must be refreshed. */ |
| int |
| tui_update_breakpoint_info (TuiWinInfoPtr win, int current_only) |
| { |
| int i; |
| int need_refresh = 0; |
| TuiSourceInfoPtr src = &win->detail.sourceInfo; |
| |
| for (i = 0; i < win->generic.contentSize; i++) |
| { |
| struct breakpoint *bp; |
| extern struct breakpoint *breakpoint_chain; |
| int mode; |
| TuiSourceElement* line; |
| |
| line = &((TuiWinElementPtr) win->generic.content[i])->whichElement.source; |
| if (current_only && !line->isExecPoint) |
| continue; |
| |
| /* Scan each breakpoint to see if the current line has something to |
| do with it. Identify enable/disabled breakpoints as well as |
| those that we already hit. */ |
| mode = 0; |
| for (bp = breakpoint_chain; |
| bp != (struct breakpoint *) NULL; |
| bp = bp->next) |
| { |
| if ((win == srcWin |
| && bp->source_file |
| && (strcmp (src->filename, bp->source_file) == 0) |
| && bp->line_number == line->lineOrAddr.lineNo) |
| || (win == disassemWin |
| && bp->address == line->lineOrAddr.addr)) |
| { |
| if (bp->enable_state == bp_disabled) |
| mode |= TUI_BP_DISABLED; |
| else |
| mode |= TUI_BP_ENABLED; |
| if (bp->hit_count) |
| mode |= TUI_BP_HIT; |
| if (bp->cond) |
| mode |= TUI_BP_CONDITIONAL; |
| if (bp->type == bp_hardware_breakpoint) |
| mode |= TUI_BP_HARDWARE; |
| } |
| } |
| if (line->hasBreak != mode) |
| { |
| line->hasBreak = mode; |
| need_refresh = 1; |
| } |
| } |
| return need_refresh; |
| } |
| |
| |
| /* |
| ** tuiSetExecInfoContent(). |
| ** Function to initialize the content of the execution info window, |
| ** based upon the input window which is either the source or |
| ** disassembly window. |
| */ |
| TuiStatus |
| tuiSetExecInfoContent (TuiWinInfoPtr winInfo) |
| { |
| TuiStatus ret = TUI_SUCCESS; |
| |
| if (winInfo->detail.sourceInfo.executionInfo != (TuiGenWinInfoPtr) NULL) |
| { |
| TuiGenWinInfoPtr execInfoPtr = winInfo->detail.sourceInfo.executionInfo; |
| |
| if (execInfoPtr->content == (OpaquePtr) NULL) |
| execInfoPtr->content = |
| (OpaquePtr) allocContent (winInfo->generic.height, |
| execInfoPtr->type); |
| if (execInfoPtr->content != (OpaquePtr) NULL) |
| { |
| int i; |
| |
| tui_update_breakpoint_info (winInfo, 1); |
| for (i = 0; i < winInfo->generic.contentSize; i++) |
| { |
| TuiWinElementPtr element; |
| TuiWinElementPtr srcElement; |
| int mode; |
| |
| element = (TuiWinElementPtr) execInfoPtr->content[i]; |
| srcElement = (TuiWinElementPtr) winInfo->generic.content[i]; |
| |
| memset(element->whichElement.simpleString, ' ', |
| sizeof(element->whichElement.simpleString)); |
| element->whichElement.simpleString[TUI_EXECINFO_SIZE - 1] = 0; |
| |
| /* Now update the exec info content based upon the state |
| of each line as indicated by the source content. */ |
| mode = srcElement->whichElement.source.hasBreak; |
| if (mode & TUI_BP_HIT) |
| element->whichElement.simpleString[TUI_BP_HIT_POS] = |
| (mode & TUI_BP_HARDWARE) ? 'H' : 'B'; |
| else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED)) |
| element->whichElement.simpleString[TUI_BP_HIT_POS] = |
| (mode & TUI_BP_HARDWARE) ? 'h' : 'b'; |
| |
| if (mode & TUI_BP_ENABLED) |
| element->whichElement.simpleString[TUI_BP_BREAK_POS] = '+'; |
| else if (mode & TUI_BP_DISABLED) |
| element->whichElement.simpleString[TUI_BP_BREAK_POS] = '-'; |
| |
| if (srcElement->whichElement.source.isExecPoint) |
| element->whichElement.simpleString[TUI_EXEC_POS] = '>'; |
| } |
| execInfoPtr->contentSize = winInfo->generic.contentSize; |
| } |
| else |
| ret = TUI_FAILURE; |
| } |
| |
| return ret; |
| } |
| |
| |
| /* |
| ** tuiShowExecInfoContent(). |
| */ |
| void |
| tuiShowExecInfoContent (TuiWinInfoPtr winInfo) |
| { |
| TuiGenWinInfoPtr execInfo = winInfo->detail.sourceInfo.executionInfo; |
| int curLine; |
| |
| werase (execInfo->handle); |
| tuiRefreshWin (execInfo); |
| for (curLine = 1; (curLine <= execInfo->contentSize); curLine++) |
| mvwaddstr (execInfo->handle, |
| curLine, |
| 0, |
| ((TuiWinElementPtr) |
| execInfo->content[curLine - 1])->whichElement.simpleString); |
| tuiRefreshWin (execInfo); |
| execInfo->contentInUse = TRUE; |
| |
| return; |
| } /* tuiShowExecInfoContent */ |
| |
| |
| /* |
| ** tuiEraseExecInfoContent(). |
| */ |
| void |
| tuiEraseExecInfoContent (TuiWinInfoPtr winInfo) |
| { |
| TuiGenWinInfoPtr execInfo = winInfo->detail.sourceInfo.executionInfo; |
| |
| werase (execInfo->handle); |
| tuiRefreshWin (execInfo); |
| |
| return; |
| } /* tuiEraseExecInfoContent */ |
| |
| /* |
| ** tuiClearExecInfoContent(). |
| */ |
| void |
| tuiClearExecInfoContent (TuiWinInfoPtr winInfo) |
| { |
| winInfo->detail.sourceInfo.executionInfo->contentInUse = FALSE; |
| tuiEraseExecInfoContent (winInfo); |
| |
| return; |
| } /* tuiClearExecInfoContent */ |
| |
| /* |
| ** tuiUpdateExecInfo(). |
| ** Function to update the execution info window |
| */ |
| void |
| tuiUpdateExecInfo (TuiWinInfoPtr winInfo) |
| { |
| tuiSetExecInfoContent (winInfo); |
| tuiShowExecInfoContent (winInfo); |
| } /* tuiUpdateExecInfo */ |
| |
| TuiStatus |
| tuiAllocSourceBuffer (TuiWinInfoPtr winInfo) |
| { |
| register char *srcLineBuf; |
| register int i, lineWidth, maxLines; |
| TuiStatus ret = TUI_FAILURE; |
| |
| maxLines = winInfo->generic.height; /* less the highlight box */ |
| lineWidth = winInfo->generic.width - 1; |
| /* |
| ** Allocate the buffer for the source lines. Do this only once since they |
| ** will be re-used for all source displays. The only other time this will |
| ** be done is when a window's size changes. |
| */ |
| if (winInfo->generic.content == (OpaquePtr) NULL) |
| { |
| srcLineBuf = (char *) xmalloc ((maxLines * lineWidth) * sizeof (char)); |
| if (srcLineBuf == (char *) NULL) |
| fputs_unfiltered ( |
| "Unable to Allocate Memory for Source or Disassembly Display.\n", |
| gdb_stderr); |
| else |
| { |
| /* allocate the content list */ |
| if ((winInfo->generic.content = |
| (OpaquePtr) allocContent (maxLines, SRC_WIN)) == (OpaquePtr) NULL) |
| { |
| tuiFree (srcLineBuf); |
| srcLineBuf = (char *) NULL; |
| fputs_unfiltered ( |
| "Unable to Allocate Memory for Source or Disassembly Display.\n", |
| gdb_stderr); |
| } |
| } |
| for (i = 0; i < maxLines; i++) |
| ((TuiWinElementPtr) |
| winInfo->generic.content[i])->whichElement.source.line = |
| srcLineBuf + (lineWidth * i); |
| ret = TUI_SUCCESS; |
| } |
| else |
| ret = TUI_SUCCESS; |
| |
| return ret; |
| } /* tuiAllocSourceBuffer */ |
| |
| |
| /* |
| ** tuiLineIsDisplayed(). |
| ** Answer whether the a particular line number or address is displayed |
| ** in the current source window. |
| */ |
| int |
| tuiLineIsDisplayed (int line, TuiWinInfoPtr winInfo, |
| int checkThreshold) |
| { |
| int isDisplayed = FALSE; |
| int i, threshold; |
| |
| if (checkThreshold) |
| threshold = SCROLL_THRESHOLD; |
| else |
| threshold = 0; |
| i = 0; |
| while (i < winInfo->generic.contentSize - threshold && !isDisplayed) |
| { |
| isDisplayed = (((TuiWinElementPtr) |
| winInfo->generic.content[i])->whichElement.source.lineOrAddr.lineNo |
| == (int) line); |
| i++; |
| } |
| |
| return isDisplayed; |
| } /* tuiLineIsDisplayed */ |
| |
| |
| /* |
| ** tuiLineIsDisplayed(). |
| ** Answer whether the a particular line number or address is displayed |
| ** in the current source window. |
| */ |
| int |
| tuiAddrIsDisplayed (CORE_ADDR addr, TuiWinInfoPtr winInfo, |
| int checkThreshold) |
| { |
| int isDisplayed = FALSE; |
| int i, threshold; |
| |
| if (checkThreshold) |
| threshold = SCROLL_THRESHOLD; |
| else |
| threshold = 0; |
| i = 0; |
| while (i < winInfo->generic.contentSize - threshold && !isDisplayed) |
| { |
| isDisplayed = (((TuiWinElementPtr) |
| winInfo->generic.content[i])->whichElement.source.lineOrAddr.addr |
| == addr); |
| i++; |
| } |
| |
| return isDisplayed; |
| } |
| |
| |
| /***************************************** |
| ** STATIC LOCAL FUNCTIONS ** |
| ******************************************/ |