The source_cache::ensure method may throw an exception through the invocation of source_cache::get_plain_source_lines. This happens when the source file is not found. The expected behaviour of "ensure" is only returning "true" or "false" according to the documentation in the header file. So far, if gdb is in source layout and a file is missing, you see some outputs like below: ,---------------------------------------------. | test.c file is loaded in the source window. | | | | int main() | | ... | |---------------------------------------------| | Remote debugging using :1234 | | __start () at /path/to/crt0.S:141 | | /path/to/crt0.S: No such file or directory. | | (gdb) p/x $pc | | $1 = 0x124 | | (gdb) n | | /path/to/crt0.S: No such file or directory. | | (gdb) p/x $pc | | $2 = 0x128 | | (gdb) [pressing arrow-down key] | | (gdb) terminate called after throwing an | | instance of 'gdb_exception_error' | `---------------------------------------------' Other issues have been encountered as well [1]. The patch from Pedro [2] which is about preventing exceptions from crossing the "readline" mitigates the situation by not causing gdb crash, but still there are lots of errors printed: ,---------------------------------------------. | test.c file is loaded in the source window. | | | | int main() | | ... | |---------------------------------------------| | Remote debugging using :1234 | | __start () at /path/to/crt0.S:141 | | /path/to/crt0.S: No such file or directory. | | (gdb) [pressing arrow-down key] | | /path/to/crt0.S: No such file or directory. | | (gdb) [pressing arrow-down key] | | /path/to/crt0.S: No such file or directory. | | (gdb) [pressing arrow-up key] | | /path/to/crt0.S: No such file or directory. | `---------------------------------------------' With the changes of this patch, the behavior is like: ,---------------------------------------------. | initially, source window is empty because | | crt0.S is not found and according to the | | program counter that is the piece of code | | being executed. | | | | later, when we break at main (see commands | | below), this window will be filled with the | | the contents of test.c file. | |---------------------------------------------| | Remote debugging using :1234 | | __start () at /path/to/crt0.S:141 | | (gdb) p/x $pc | | $1 = 0x124 | | (gdb) n | | (gdb) p/x $pc | | $2 = 0x128 | | (gdb) b main | | Breakpoint 1 at 0x334: file test.c, line 8. | | (gdb) cont | | Continuing. | | Breakpoint 1, main () at hello.c:8 | | (gdb) n | | (gdb) | `---------------------------------------------' There is no crash and the error message is completely gone. Maybe it is good practice that the error is shown inside the source window. I tested this change against gdb.base/list-missing-source.exp and there was no regression. [1] It has also been observed in the past that the register values are not transferred from qemu's gdb stub, see: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/issues/226 [2] https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=2f267673f0fdee9287e6d404ecd4f2d29da0d2f2 gdb/ChangeLog: * source-cache.c (source_cache::ensure): Surround get_plain_source_lines with a try/catch. (source_cache::get_line_charpos): Get rid of try/catch and only check for the return value of "ensure". * tui/tui-source.c (tui_source_window::set_contents): Simplify "nlines" calculation. gdb/testsuite/ChangeLog: * gdb.tui/tui-missing-src.exp: Add the "missing source file" test for the TUI.
219 lines
5.8 KiB
C
219 lines
5.8 KiB
C
/* TUI display source window.
|
|
|
|
Copyright (C) 1998-2020 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 3 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, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include <math.h>
|
|
#include <ctype.h>
|
|
#include "symtab.h"
|
|
#include "frame.h"
|
|
#include "breakpoint.h"
|
|
#include "source.h"
|
|
#include "objfiles.h"
|
|
#include "filenames.h"
|
|
#include "source-cache.h"
|
|
|
|
#include "tui/tui.h"
|
|
#include "tui/tui-data.h"
|
|
#include "tui/tui-io.h"
|
|
#include "tui/tui-stack.h"
|
|
#include "tui/tui-win.h"
|
|
#include "tui/tui-winsource.h"
|
|
#include "tui/tui-source.h"
|
|
#include "gdb_curses.h"
|
|
|
|
/* Function to display source in the source window. */
|
|
bool
|
|
tui_source_window::set_contents (struct gdbarch *arch,
|
|
const struct symtab_and_line &sal)
|
|
{
|
|
struct symtab *s = sal.symtab;
|
|
int line_no = sal.line;
|
|
|
|
if (s == NULL)
|
|
return false;
|
|
|
|
int line_width, nlines;
|
|
|
|
line_width = width - TUI_EXECINFO_SIZE - 1;
|
|
/* Take hilite (window border) into account, when
|
|
calculating the number of lines. */
|
|
nlines = height - 2;
|
|
|
|
std::string srclines;
|
|
const std::vector<off_t> *offsets;
|
|
if (!g_source_cache.get_source_lines (s, line_no, line_no + nlines,
|
|
&srclines)
|
|
|| !g_source_cache.get_line_charpos (s, &offsets))
|
|
return false;
|
|
|
|
int cur_line_no, cur_line;
|
|
struct tui_locator_window *locator
|
|
= tui_locator_win_info_ptr ();
|
|
const char *s_filename = symtab_to_filename_for_display (s);
|
|
|
|
title = s_filename;
|
|
|
|
m_fullname = make_unique_xstrdup (symtab_to_fullname (s));
|
|
|
|
cur_line = 0;
|
|
gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
|
|
start_line_or_addr.loa = LOA_LINE;
|
|
cur_line_no = start_line_or_addr.u.line_no = line_no;
|
|
|
|
int digits = 0;
|
|
if (compact_source)
|
|
{
|
|
/* Solaris 11+gcc 5.5 has ambiguous overloads of log10, so we
|
|
cast to double to get the right one. */
|
|
double l = log10 ((double) offsets->size ());
|
|
digits = 1 + (int) l;
|
|
}
|
|
|
|
const char *iter = srclines.c_str ();
|
|
content.resize (nlines);
|
|
while (cur_line < nlines)
|
|
{
|
|
struct tui_source_element *element
|
|
= &content[cur_line];
|
|
|
|
std::string text;
|
|
if (*iter != '\0')
|
|
text = tui_copy_source_line (&iter, cur_line_no,
|
|
horizontal_offset,
|
|
line_width, digits);
|
|
|
|
/* Set whether element is the execution point
|
|
and whether there is a break point on it. */
|
|
element->line_or_addr.loa = LOA_LINE;
|
|
element->line_or_addr.u.line_no = cur_line_no;
|
|
element->is_exec_point
|
|
= (filename_cmp (locator->full_name.c_str (),
|
|
symtab_to_fullname (s)) == 0
|
|
&& cur_line_no == locator->line_no);
|
|
|
|
content[cur_line].line = std::move (text);
|
|
|
|
cur_line++;
|
|
cur_line_no++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/* Answer whether the source is currently displayed in the source
|
|
window. */
|
|
bool
|
|
tui_source_window::showing_source_p (const char *fullname) const
|
|
{
|
|
return (!content.empty ()
|
|
&& (filename_cmp (tui_locator_win_info_ptr ()->full_name.c_str (),
|
|
fullname) == 0));
|
|
}
|
|
|
|
|
|
/* Scroll the source forward or backward vertically. */
|
|
void
|
|
tui_source_window::do_scroll_vertical (int num_to_scroll)
|
|
{
|
|
if (!content.empty ())
|
|
{
|
|
struct symtab *s;
|
|
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
|
|
struct gdbarch *arch = gdbarch;
|
|
|
|
if (cursal.symtab == NULL)
|
|
{
|
|
struct frame_info *fi = get_selected_frame (NULL);
|
|
s = find_pc_line_symtab (get_frame_pc (fi));
|
|
arch = get_frame_arch (fi);
|
|
}
|
|
else
|
|
s = cursal.symtab;
|
|
|
|
int line_no = start_line_or_addr.u.line_no + num_to_scroll;
|
|
const std::vector<off_t> *offsets;
|
|
if (g_source_cache.get_line_charpos (s, &offsets)
|
|
&& line_no > offsets->size ())
|
|
line_no = start_line_or_addr.u.line_no;
|
|
if (line_no <= 0)
|
|
line_no = 1;
|
|
|
|
cursal.line = line_no;
|
|
find_line_pc (cursal.symtab, cursal.line, &cursal.pc);
|
|
for (struct tui_source_window_base *win_info : tui_source_windows ())
|
|
win_info->update_source_window_as_is (arch, cursal);
|
|
}
|
|
}
|
|
|
|
bool
|
|
tui_source_window::location_matches_p (struct bp_location *loc, int line_no)
|
|
{
|
|
return (content[line_no].line_or_addr.loa == LOA_LINE
|
|
&& content[line_no].line_or_addr.u.line_no == loc->line_number
|
|
&& loc->symtab != NULL
|
|
&& filename_cmp (m_fullname.get (),
|
|
symtab_to_fullname (loc->symtab)) == 0);
|
|
}
|
|
|
|
/* See tui-source.h. */
|
|
|
|
bool
|
|
tui_source_window::line_is_displayed (int line) const
|
|
{
|
|
if (content.size () < SCROLL_THRESHOLD)
|
|
return false;
|
|
|
|
for (size_t i = 0; i < content.size () - SCROLL_THRESHOLD; ++i)
|
|
{
|
|
if (content[i].line_or_addr.loa == LOA_LINE
|
|
&& content[i].line_or_addr.u.line_no == line)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
tui_source_window::maybe_update (struct frame_info *fi, symtab_and_line sal)
|
|
{
|
|
int start_line = (sal.line - ((height - 2) / 2)) + 1;
|
|
if (start_line <= 0)
|
|
start_line = 1;
|
|
|
|
bool source_already_displayed = (sal.symtab != 0
|
|
&& showing_source_p (m_fullname.get ()));
|
|
|
|
if (!(source_already_displayed && line_is_displayed (sal.line)))
|
|
{
|
|
sal.line = start_line;
|
|
update_source_window (get_frame_arch (fi), sal);
|
|
}
|
|
else
|
|
{
|
|
struct tui_line_or_address l;
|
|
|
|
l.loa = LOA_LINE;
|
|
l.u.line_no = sal.line;
|
|
set_is_exec_point_at (l);
|
|
}
|
|
}
|