/* 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 via 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 first. */ #include "config.h" #ifdef HAVE_NCURSES_H #include #else #ifdef HAVE_CURSES_H #include #endif #endif #include "defs.h" #include #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 (get_frame_pc (deprecated_selected_frame)); 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 ** ******************************************/