blob: e3a19b3ebaa4853cb5bfd59aa21127a92d68fe2f [file] [log] [blame]
/* Disassembly display.
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 "symtab.h"
#include "breakpoint.h"
#include "frame.h"
#include "value.h"
#include "tui.h"
#include "tuiData.h"
#include "tuiWin.h"
#include "tuiLayout.h"
#include "tuiSourceWin.h"
#include "tuiStack.h"
#include "tui-file.h"
/*****************************************
** STATIC LOCAL FUNCTIONS FORWARD DECLS **
******************************************/
static struct breakpoint *_hasBreak (CORE_ADDR);
/*****************************************
** PUBLIC FUNCTIONS **
******************************************/
/*
** tuiSetDisassemContent().
** Function to set the disassembly window's content.
*/
TuiStatus
tuiSetDisassemContent (struct symtab *s, CORE_ADDR startAddr)
{
TuiStatus ret = TUI_FAILURE;
struct ui_file *gdb_dis_out;
if (startAddr != 0)
{
register int i, desc;
if ((ret = tuiAllocSourceBuffer (disassemWin)) == TUI_SUCCESS)
{
register int offset = disassemWin->detail.sourceInfo.horizontalOffset;
register int threshold, curLine = 0, lineWidth, maxLines;
CORE_ADDR newpc, pc;
disassemble_info asmInfo;
TuiGenWinInfoPtr locator = locatorWinInfoPtr ();
extern void strcat_address (CORE_ADDR, char *, int);
extern void strcat_address_numeric (CORE_ADDR, int, char *, int);
int curLen = 0;
int tab_len = tuiDefaultTabLen ();
maxLines = disassemWin->generic.height - 2; /* account for hilite */
lineWidth = disassemWin->generic.width - 1;
threshold = (lineWidth - 1) + offset;
/* now init the ui_file structure */
gdb_dis_out = tui_sfileopen (threshold);
asmInfo = tm_print_insn_info;
asmInfo.stream = gdb_dis_out;
disassemWin->detail.sourceInfo.startLineOrAddr.addr = startAddr;
/* Now construct each line */
for (curLine = 0, pc = startAddr; (curLine < maxLines);)
{
TuiWinElementPtr element = (TuiWinElementPtr) disassemWin->generic.content[curLine];
struct breakpoint *bp;
print_address (pc, gdb_dis_out);
curLen = strlen (tui_file_get_strbuf (gdb_dis_out));
i = curLen - ((curLen / tab_len) * tab_len);
/* adjust buffer length if necessary */
tui_file_adjust_strbuf ((tab_len - i > 0) ? (tab_len - i) : 0, gdb_dis_out);
/* Add spaces to make the instructions start onthe same column */
while (i < tab_len)
{
tui_file_get_strbuf (gdb_dis_out)[curLen] = ' ';
i++;
curLen++;
}
tui_file_get_strbuf (gdb_dis_out)[curLen] = '\0';
newpc = pc + ((*tm_print_insn) (pc, &asmInfo));
/* Now copy the line taking the offset into account */
if (strlen (tui_file_get_strbuf (gdb_dis_out)) > offset)
strcpy (element->whichElement.source.line,
&(tui_file_get_strbuf (gdb_dis_out)[offset]));
else
element->whichElement.source.line[0] = '\0';
element->whichElement.source.lineOrAddr.addr = pc;
element->whichElement.source.isExecPoint =
(pc == (CORE_ADDR) ((TuiWinElementPtr) locator->content[0])->whichElement.locator.addr);
bp = _hasBreak (pc);
element->whichElement.source.hasBreak =
(bp != (struct breakpoint *) NULL &&
(!element->whichElement.source.isExecPoint ||
(bp->disposition != disp_del || bp->hit_count <= 0)));
curLine++;
pc = newpc;
/* reset the buffer to empty */
tui_file_get_strbuf (gdb_dis_out)[0] = '\0';
}
ui_file_delete (gdb_dis_out);
gdb_dis_out = NULL;
disassemWin->generic.contentSize = curLine;
ret = TUI_SUCCESS;
}
}
return ret;
} /* tuiSetDisassemContent */
/*
** tuiShowDisassem().
** Function to display the disassembly window with disassembled code.
*/
void
tuiShowDisassem (CORE_ADDR startAddr)
{
struct symtab *s = find_pc_symtab (startAddr);
TuiWinInfoPtr winWithFocus = tuiWinWithFocus ();
TuiLineOrAddress val;
val.addr = startAddr;
tuiAddWinToLayout (DISASSEM_WIN);
tuiUpdateSourceWindow (disassemWin, s, val, FALSE);
/*
** if the focus was in the src win, put it in the asm win, if the
** source view isn't split
*/
if (currentLayout () != SRC_DISASSEM_COMMAND && winWithFocus == srcWin)
tuiSetWinFocusTo (disassemWin);
return;
} /* tuiShowDisassem */
/*
** tuiShowDisassemAndUpdateSource().
** Function to display the disassembly window.
*/
void
tuiShowDisassemAndUpdateSource (CORE_ADDR startAddr)
{
struct symtab_and_line sal;
tuiShowDisassem (startAddr);
if (currentLayout () == SRC_DISASSEM_COMMAND)
{
TuiLineOrAddress val;
TuiGenWinInfoPtr locator = locatorWinInfoPtr ();
/*
** Update what is in the source window if it is displayed too,
** note that it follows what is in the disassembly window and visa-versa
*/
sal = find_pc_line (startAddr, 0);
val.lineNo = sal.line;
tuiUpdateSourceWindow (srcWin, sal.symtab, val, TRUE);
if (sal.symtab)
{
current_source_symtab = sal.symtab;
tuiUpdateLocatorFilename (sal.symtab->filename);
}
else
tuiUpdateLocatorFilename ("?");
}
return;
} /* tuiShowDisassemAndUpdateSource */
/*
** tuiGetBeginAsmAddress().
*/
CORE_ADDR
tuiGetBeginAsmAddress (void)
{
TuiGenWinInfoPtr locator;
TuiLocatorElementPtr element;
CORE_ADDR addr;
locator = locatorWinInfoPtr ();
element = &((TuiWinElementPtr) locator->content[0])->whichElement.locator;
if (element->addr == 0)
{
struct minimal_symbol *main_symbol;
/* Find address of the start of program.
Note: this should be language specific. */
main_symbol = lookup_minimal_symbol ("main", NULL, NULL);
if (main_symbol == 0)
main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL);
if (main_symbol == 0)
main_symbol = lookup_minimal_symbol ("_start", NULL, NULL);
if (main_symbol)
addr = SYMBOL_VALUE_ADDRESS (main_symbol);
else
addr = 0;
}
else /* the target is executing */
addr = element->addr;
return addr;
}
/*
** tuiVerticalDisassemScroll().
** Scroll the disassembly forward or backward vertically
*/
void
tuiVerticalDisassemScroll (TuiScrollDirection scrollDirection,
int numToScroll)
{
if (disassemWin->generic.content != (OpaquePtr) NULL)
{
CORE_ADDR pc, lowAddr;
TuiWinContent content;
struct symtab *s;
content = (TuiWinContent) disassemWin->generic.content;
if (current_source_symtab == (struct symtab *) NULL)
s = find_pc_symtab (selected_frame->pc);
else
s = current_source_symtab;
pc = content[0]->whichElement.source.lineOrAddr.addr;
if (find_pc_partial_function (pc, (char **) NULL, &lowAddr,
(CORE_ADDR) 0) == 0)
error ("No function contains program counter for selected frame.\n");
else
{
register int line = 0;
register CORE_ADDR newLow;
bfd_byte buffer[4];
TuiLineOrAddress val;
newLow = pc;
if (scrollDirection == FORWARD_SCROLL)
{
for (; line < numToScroll; line++)
newLow += sizeof (bfd_getb32 (buffer));
}
else
{
for (; newLow != 0 && line < numToScroll; line++)
newLow -= sizeof (bfd_getb32 (buffer));
}
val.addr = newLow;
tuiUpdateSourceWindowAsIs (disassemWin, s, val, FALSE);
}
}
return;
} /* tuiVerticalDisassemScroll */
/*****************************************
** STATIC LOCAL FUNCTIONS **
******************************************/
/*
** _hasBreak().
** Answer whether there is a break point at the input line in the
** source file indicated
*/
static struct breakpoint *
_hasBreak (CORE_ADDR addr)
{
struct breakpoint *bpWithBreak = (struct breakpoint *) NULL;
struct breakpoint *bp;
extern struct breakpoint *breakpoint_chain;
for (bp = breakpoint_chain;
(bp != (struct breakpoint *) NULL &&
bpWithBreak == (struct breakpoint *) NULL);
bp = bp->next)
if (addr == bp->address)
bpWithBreak = bp;
return bpWithBreak;
} /* _hasBreak */