forked from Imagelibrary/binutils-gdb
Compare commits
6 Commits
gdb-15.2-r
...
users/amer
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e6430952a | ||
|
|
6496753f01 | ||
|
|
bf803c840c | ||
|
|
8de61c8491 | ||
|
|
aee7ee692a | ||
|
|
255f319779 |
@@ -26,3 +26,30 @@ else
|
|||||||
AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.])
|
AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.])
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([AC_DEBUGINFOD_SECTION],
|
||||||
|
[
|
||||||
|
# Handle optional debuginfod support as well as optional section downloading support
|
||||||
|
AC_ARG_WITH([debuginfod],
|
||||||
|
AC_HELP_STRING([--with-debuginfod], [Enable debuginfo lookups with debuginfod (auto/yes/no)]),
|
||||||
|
[], [with_debuginfod=auto])
|
||||||
|
AC_MSG_CHECKING([whether to use debuginfod])
|
||||||
|
AC_MSG_RESULT([$with_debuginfod])
|
||||||
|
|
||||||
|
if test "x$with_debuginfod" != xno; then
|
||||||
|
PKG_CHECK_MODULES([DEBUGINFOD], [libdebuginfod >= 0.188],
|
||||||
|
[AC_DEFINE([HAVE_DEBUGINFOD_FIND_SECTION], [1],
|
||||||
|
[Define to 1 if debuginfod section downloading is supported.])],
|
||||||
|
[AC_MSG_WARN([libdebuginfod is missing or some features may be unavailable.])])
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES([DEBUGINFOD], [libdebuginfod >= 0.179],
|
||||||
|
[AC_DEFINE([HAVE_LIBDEBUGINFOD], [1], [Define to 1 if debuginfod is enabled.])],
|
||||||
|
[if test "x$with_debuginfod" = xyes; then
|
||||||
|
AC_MSG_ERROR(["--with-debuginfod was given, but libdebuginfod is missing or unusable."])
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([libdebuginfod is missing or unusable; some features may be unavailable.])
|
||||||
|
fi])
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|||||||
@@ -263,6 +263,19 @@ cli_ui_out::do_redirect (ui_file *outstream)
|
|||||||
m_streams.pop_back ();
|
m_streams.pop_back ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cli_ui_out::do_redirect_to_buffer (buffer_file *buf_file)
|
||||||
|
{
|
||||||
|
if (buf_file != nullptr)
|
||||||
|
{
|
||||||
|
gdb_assert (m_streams.size () >= 1);
|
||||||
|
buf_file->set_stream (m_streams.back ());
|
||||||
|
do_redirect (buf_file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_streams.pop_back ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize a progress update to be displayed with
|
/* Initialize a progress update to be displayed with
|
||||||
cli_ui_out::do_progress_notify. */
|
cli_ui_out::do_progress_notify. */
|
||||||
|
|
||||||
@@ -299,7 +312,8 @@ cli_ui_out::do_progress_notify (const std::string &msg,
|
|||||||
double howmuch, double total)
|
double howmuch, double total)
|
||||||
{
|
{
|
||||||
int chars_per_line = get_chars_per_line ();
|
int chars_per_line = get_chars_per_line ();
|
||||||
struct ui_file *stream = m_streams.back ();
|
struct ui_file *stream
|
||||||
|
= buffer_file::get_unbuffered_stream (m_streams.back ());
|
||||||
cli_progress_info &info (m_progress_info.back ());
|
cli_progress_info &info (m_progress_info.back ());
|
||||||
|
|
||||||
if (chars_per_line > MAX_CHARS_PER_LINE)
|
if (chars_per_line > MAX_CHARS_PER_LINE)
|
||||||
@@ -384,7 +398,8 @@ cli_ui_out::do_progress_notify (const std::string &msg,
|
|||||||
void
|
void
|
||||||
cli_ui_out::clear_progress_notify ()
|
cli_ui_out::clear_progress_notify ()
|
||||||
{
|
{
|
||||||
struct ui_file *stream = m_streams.back ();
|
struct ui_file *stream
|
||||||
|
= buffer_file::get_unbuffered_stream (m_streams.back ());
|
||||||
int chars_per_line = get_chars_per_line ();
|
int chars_per_line = get_chars_per_line ();
|
||||||
|
|
||||||
scoped_restore save_pagination
|
scoped_restore save_pagination
|
||||||
@@ -413,10 +428,11 @@ void
|
|||||||
cli_ui_out::do_progress_end ()
|
cli_ui_out::do_progress_end ()
|
||||||
{
|
{
|
||||||
struct ui_file *stream = m_streams.back ();
|
struct ui_file *stream = m_streams.back ();
|
||||||
m_progress_info.pop_back ();
|
|
||||||
|
|
||||||
if (stream->isatty ())
|
if (stream->isatty ())
|
||||||
clear_progress_notify ();
|
clear_progress_notify ();
|
||||||
|
|
||||||
|
m_progress_info.pop_back ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* local functions */
|
/* local functions */
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ protected:
|
|||||||
virtual void do_wrap_hint (int indent) override;
|
virtual void do_wrap_hint (int indent) override;
|
||||||
virtual void do_flush () override;
|
virtual void do_flush () override;
|
||||||
virtual void do_redirect (struct ui_file *outstream) override;
|
virtual void do_redirect (struct ui_file *outstream) override;
|
||||||
|
virtual void do_redirect_to_buffer (buffer_file *buf_file) override;
|
||||||
|
|
||||||
virtual void do_progress_start () override;
|
virtual void do_progress_start () override;
|
||||||
virtual void do_progress_notify (const std::string &, const char *,
|
virtual void do_progress_notify (const std::string &, const char *,
|
||||||
|
|||||||
@@ -99,6 +99,9 @@
|
|||||||
/* define if the compiler supports basic C++11 syntax */
|
/* define if the compiler supports basic C++11 syntax */
|
||||||
#undef HAVE_CXX11
|
#undef HAVE_CXX11
|
||||||
|
|
||||||
|
/* Define to 1 if debuginfod section downloading is supported. */
|
||||||
|
#undef HAVE_DEBUGINFOD_FIND_SECTION
|
||||||
|
|
||||||
/* Define to 1 if you have the declaration of `ADDR_NO_RANDOMIZE', and to 0 if
|
/* Define to 1 if you have the declaration of `ADDR_NO_RANDOMIZE', and to 0 if
|
||||||
you don't. */
|
you don't. */
|
||||||
#undef HAVE_DECL_ADDR_NO_RANDOMIZE
|
#undef HAVE_DECL_ADDR_NO_RANDOMIZE
|
||||||
|
|||||||
102
gdb/configure
vendored
102
gdb/configure
vendored
@@ -18349,7 +18349,7 @@ esac
|
|||||||
|
|
||||||
# Handle optional debuginfod support
|
# Handle optional debuginfod support
|
||||||
|
|
||||||
# Handle optional debuginfod support
|
# Handle optional debuginfod support as well as optional section downloading support
|
||||||
|
|
||||||
# Check whether --with-debuginfod was given.
|
# Check whether --with-debuginfod was given.
|
||||||
if test "${with_debuginfod+set}" = set; then :
|
if test "${with_debuginfod+set}" = set; then :
|
||||||
@@ -18365,6 +18365,106 @@ $as_echo "$with_debuginfod" >&6; }
|
|||||||
|
|
||||||
if test "x$with_debuginfod" != xno; then
|
if test "x$with_debuginfod" != xno; then
|
||||||
|
|
||||||
|
pkg_failed=no
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.188" >&5
|
||||||
|
$as_echo_n "checking for libdebuginfod >= 0.188... " >&6; }
|
||||||
|
|
||||||
|
if test -n "$DEBUGINFOD_CFLAGS"; then
|
||||||
|
pkg_cv_DEBUGINFOD_CFLAGS="$DEBUGINFOD_CFLAGS"
|
||||||
|
elif test -n "$PKG_CONFIG"; then
|
||||||
|
if test -n "$PKG_CONFIG" && \
|
||||||
|
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.188\""; } >&5
|
||||||
|
($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.188") 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||||
|
test $ac_status = 0; }; then
|
||||||
|
pkg_cv_DEBUGINFOD_CFLAGS=`$PKG_CONFIG --cflags "libdebuginfod >= 0.188" 2>/dev/null`
|
||||||
|
test "x$?" != "x0" && pkg_failed=yes
|
||||||
|
else
|
||||||
|
pkg_failed=yes
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pkg_failed=untried
|
||||||
|
fi
|
||||||
|
if test -n "$DEBUGINFOD_LIBS"; then
|
||||||
|
pkg_cv_DEBUGINFOD_LIBS="$DEBUGINFOD_LIBS"
|
||||||
|
elif test -n "$PKG_CONFIG"; then
|
||||||
|
if test -n "$PKG_CONFIG" && \
|
||||||
|
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.188\""; } >&5
|
||||||
|
($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.188") 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||||
|
test $ac_status = 0; }; then
|
||||||
|
pkg_cv_DEBUGINFOD_LIBS=`$PKG_CONFIG --libs "libdebuginfod >= 0.188" 2>/dev/null`
|
||||||
|
test "x$?" != "x0" && pkg_failed=yes
|
||||||
|
else
|
||||||
|
pkg_failed=yes
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pkg_failed=untried
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $pkg_failed = no; then
|
||||||
|
pkg_save_LDFLAGS="$LDFLAGS"
|
||||||
|
LDFLAGS="$LDFLAGS $pkg_cv_DEBUGINFOD_LIBS"
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_link "$LINENO"; then :
|
||||||
|
|
||||||
|
else
|
||||||
|
pkg_failed=yes
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext \
|
||||||
|
conftest$ac_exeext conftest.$ac_ext
|
||||||
|
LDFLAGS=$pkg_save_LDFLAGS
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if test $pkg_failed = yes; then
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||||
|
$as_echo "no" >&6; }
|
||||||
|
|
||||||
|
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||||
|
_pkg_short_errors_supported=yes
|
||||||
|
else
|
||||||
|
_pkg_short_errors_supported=no
|
||||||
|
fi
|
||||||
|
if test $_pkg_short_errors_supported = yes; then
|
||||||
|
DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdebuginfod >= 0.188" 2>&1`
|
||||||
|
else
|
||||||
|
DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdebuginfod >= 0.188" 2>&1`
|
||||||
|
fi
|
||||||
|
# Put the nasty error message in config.log where it belongs
|
||||||
|
echo "$DEBUGINFOD_PKG_ERRORS" >&5
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libdebuginfod is missing or some features may be unavailable." >&5
|
||||||
|
$as_echo "$as_me: WARNING: libdebuginfod is missing or some features may be unavailable." >&2;}
|
||||||
|
elif test $pkg_failed = untried; then
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||||
|
$as_echo "no" >&6; }
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libdebuginfod is missing or some features may be unavailable." >&5
|
||||||
|
$as_echo "$as_me: WARNING: libdebuginfod is missing or some features may be unavailable." >&2;}
|
||||||
|
else
|
||||||
|
DEBUGINFOD_CFLAGS=$pkg_cv_DEBUGINFOD_CFLAGS
|
||||||
|
DEBUGINFOD_LIBS=$pkg_cv_DEBUGINFOD_LIBS
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||||
|
$as_echo "yes" >&6; }
|
||||||
|
|
||||||
|
$as_echo "#define HAVE_DEBUGINFOD_FIND_SECTION 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
pkg_failed=no
|
pkg_failed=no
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.179" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.179" >&5
|
||||||
$as_echo_n "checking for libdebuginfod >= 0.179... " >&6; }
|
$as_echo_n "checking for libdebuginfod >= 0.179... " >&6; }
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ case $host_os in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
# Handle optional debuginfod support
|
# Handle optional debuginfod support
|
||||||
AC_DEBUGINFOD
|
AC_DEBUGINFOD_SECTION
|
||||||
|
|
||||||
# Libunwind support for ia64.
|
# Libunwind support for ia64.
|
||||||
AC_ARG_WITH(libunwind-ia64,
|
AC_ARG_WITH(libunwind-ia64,
|
||||||
|
|||||||
@@ -34,12 +34,14 @@ static cmd_list_element *show_debuginfod_prefix_list;
|
|||||||
static const char debuginfod_on[] = "on";
|
static const char debuginfod_on[] = "on";
|
||||||
static const char debuginfod_off[] = "off";
|
static const char debuginfod_off[] = "off";
|
||||||
static const char debuginfod_ask[] = "ask";
|
static const char debuginfod_ask[] = "ask";
|
||||||
|
static const char debuginfod_lazy[] = "lazy";
|
||||||
|
|
||||||
static const char *debuginfod_enabled_enum[] =
|
static const char *debuginfod_enabled_enum[] =
|
||||||
{
|
{
|
||||||
debuginfod_on,
|
debuginfod_on,
|
||||||
debuginfod_off,
|
debuginfod_off,
|
||||||
debuginfod_ask,
|
debuginfod_ask,
|
||||||
|
debuginfod_lazy,
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,6 +82,15 @@ debuginfod_exec_query (const unsigned char *build_id,
|
|||||||
return scoped_fd (-ENOSYS);
|
return scoped_fd (-ENOSYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scoped_fd
|
||||||
|
debuginfod_section_query (const unsigned char *build_id,
|
||||||
|
int build_id_len,
|
||||||
|
const char *filename,
|
||||||
|
const char *section_name,
|
||||||
|
gdb::unique_xmalloc_ptr<char> *destname)
|
||||||
|
{
|
||||||
|
return scoped_fd (-ENOSYS);
|
||||||
|
}
|
||||||
#define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
|
#define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -148,7 +159,8 @@ progressfn (debuginfod_client *c, long cur, long total)
|
|||||||
|
|
||||||
if (check_quit_flag ())
|
if (check_quit_flag ())
|
||||||
{
|
{
|
||||||
gdb_printf ("Cancelling download of %s %s...\n",
|
ui_file *outstream = buffer_file::get_unbuffered_stream (gdb_stdout);
|
||||||
|
gdb_printf (outstream, "Cancelling download of %s %s...\n",
|
||||||
data->desc, styled_fname.c_str ());
|
data->desc, styled_fname.c_str ());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -264,10 +276,14 @@ static void
|
|||||||
print_outcome (int fd, const char *desc, const char *fname)
|
print_outcome (int fd, const char *desc, const char *fname)
|
||||||
{
|
{
|
||||||
if (fd < 0 && fd != -ENOENT)
|
if (fd < 0 && fd != -ENOENT)
|
||||||
gdb_printf (_("Download failed: %s. Continuing without %s %ps.\n"),
|
{
|
||||||
safe_strerror (-fd),
|
ui_file *outstream = buffer_file::get_unbuffered_stream (gdb_stdout);
|
||||||
desc,
|
gdb_printf (outstream,
|
||||||
styled_string (file_name_style.style (), fname));
|
_("Download failed: %s. Continuing without %s %ps.\n"),
|
||||||
|
safe_strerror (-fd),
|
||||||
|
desc,
|
||||||
|
styled_string (file_name_style.style (), fname));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See debuginfod-support.h */
|
/* See debuginfod-support.h */
|
||||||
@@ -401,6 +417,56 @@ debuginfod_exec_query (const unsigned char *build_id,
|
|||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See debuginfod-support.h */
|
||||||
|
|
||||||
|
scoped_fd
|
||||||
|
debuginfod_section_query (const unsigned char *build_id,
|
||||||
|
int build_id_len,
|
||||||
|
const char *filename,
|
||||||
|
const char *section_name,
|
||||||
|
gdb::unique_xmalloc_ptr<char> *destname)
|
||||||
|
{
|
||||||
|
#if !defined (HAVE_DEBUGINFOD_FIND_SECTION)
|
||||||
|
return scoped_fd (-ENOSYS);
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (debuginfod_enabled != debuginfod_lazy || !debuginfod_is_enabled ())
|
||||||
|
return scoped_fd (-ENOSYS);
|
||||||
|
|
||||||
|
debuginfod_client *c = get_debuginfod_client ();
|
||||||
|
|
||||||
|
if (c == nullptr)
|
||||||
|
return scoped_fd (-ENOMEM);
|
||||||
|
|
||||||
|
char *dname = nullptr;
|
||||||
|
std::string desc = std::string ("section ") + section_name + " for";
|
||||||
|
scoped_fd fd;
|
||||||
|
gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
|
||||||
|
|
||||||
|
{
|
||||||
|
user_data data (desc.c_str (), filename);
|
||||||
|
debuginfod_set_user_data (c, &data);
|
||||||
|
if (target_supports_terminal_ours ())
|
||||||
|
{
|
||||||
|
term_state.emplace ();
|
||||||
|
target_terminal::ours ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = scoped_fd (debuginfod_find_section (c, build_id, build_id_len,
|
||||||
|
section_name, &dname));
|
||||||
|
debuginfod_set_user_data (c, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_outcome (fd.get (), desc.c_str (), filename);
|
||||||
|
|
||||||
|
if (fd.get () >= 0 && destname != nullptr)
|
||||||
|
destname->reset (dname);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
#endif /* HAVE_DEBUGINFOD_FIND_SECTION */
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Set callback for "set debuginfod enabled". */
|
/* Set callback for "set debuginfod enabled". */
|
||||||
@@ -409,6 +475,14 @@ static void
|
|||||||
set_debuginfod_enabled (const char *value)
|
set_debuginfod_enabled (const char *value)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LIBDEBUGINFOD)
|
#if defined(HAVE_LIBDEBUGINFOD)
|
||||||
|
#if !defined(HAVE_DEBUGINFOD_FIND_SECTION)
|
||||||
|
if (value == debuginfod_lazy)
|
||||||
|
{
|
||||||
|
debuginfod_enabled = debuginfod_on;
|
||||||
|
error (_("Support for lazy downloading is not compiled into GDB. " \
|
||||||
|
"Defaulting to \"on\"."));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
debuginfod_enabled = value;
|
debuginfod_enabled = value;
|
||||||
#else
|
#else
|
||||||
/* Disabling debuginfod when gdb is not built with it is a no-op. */
|
/* Disabling debuginfod when gdb is not built with it is a no-op. */
|
||||||
@@ -508,8 +582,12 @@ _initialize_debuginfod ()
|
|||||||
_("Set whether to use debuginfod."),
|
_("Set whether to use debuginfod."),
|
||||||
_("Show whether to use debuginfod."),
|
_("Show whether to use debuginfod."),
|
||||||
_("\
|
_("\
|
||||||
When on, enable the use of debuginfod to download missing debug info and\n\
|
When set to \"on\", enable the use of debuginfod to download missing\n\
|
||||||
source files."),
|
debug info and source files. \"off\" disables the use of debuginfod.\n\
|
||||||
|
When set to \"ask\", a prompt may ask whether to enable or disable\n\
|
||||||
|
debuginfod. When set to \"lazy\", debug info downloading will be\n\
|
||||||
|
deferred until it is required. GDB may also download components of\n\
|
||||||
|
debug info instead of entire files." ),
|
||||||
set_debuginfod_enabled,
|
set_debuginfod_enabled,
|
||||||
get_debuginfod_enabled,
|
get_debuginfod_enabled,
|
||||||
show_debuginfod_enabled,
|
show_debuginfod_enabled,
|
||||||
|
|||||||
@@ -81,4 +81,28 @@ extern scoped_fd debuginfod_exec_query (const unsigned char *build_id,
|
|||||||
const char *filename,
|
const char *filename,
|
||||||
gdb::unique_xmalloc_ptr<char>
|
gdb::unique_xmalloc_ptr<char>
|
||||||
*destname);
|
*destname);
|
||||||
|
|
||||||
|
/* Query debuginfod servers for the binary contents of a ELF/DWARF section
|
||||||
|
from a file matching BUILD_ID. BUILD_ID can be given as a binary blob
|
||||||
|
or a null-terminated string. If given as a binary blob, BUILD_ID_LEN
|
||||||
|
should be the number of bytes. If given as a null-terminated string,
|
||||||
|
BUILD_ID_LEN should be 0.
|
||||||
|
|
||||||
|
FILENAME should be the name or path associated with the file matching
|
||||||
|
BUILD_ID. It is used for printing messages to the user.
|
||||||
|
|
||||||
|
SECTION_NAME should be the name of an ELF/DWARF section.
|
||||||
|
|
||||||
|
If the file is successfully retrieved, return a file descriptor and store
|
||||||
|
the file's local path in DESTNAME. If unsuccessful, print an error message
|
||||||
|
and return a negative errno. If GDB is not built with debuginfod or
|
||||||
|
libdebuginfod does not support section queries, this function returns
|
||||||
|
-ENOSYS. */
|
||||||
|
|
||||||
|
extern scoped_fd debuginfod_section_query (const unsigned char *build_id,
|
||||||
|
int build_id_len,
|
||||||
|
const char *filename,
|
||||||
|
const char *section_name,
|
||||||
|
gdb::unique_xmalloc_ptr<char>
|
||||||
|
*destname);
|
||||||
#endif /* DEBUGINFOD_SUPPORT_H */
|
#endif /* DEBUGINFOD_SUPPORT_H */
|
||||||
|
|||||||
@@ -49332,10 +49332,15 @@ debug info or source files. By default, @code{debuginfod enabled} is set to
|
|||||||
attempting to perform the next query. By default, @code{debuginfod enabled}
|
attempting to perform the next query. By default, @code{debuginfod enabled}
|
||||||
is set to @code{ask} for interactive sessions.
|
is set to @code{ask} for interactive sessions.
|
||||||
|
|
||||||
|
@item set debuginfod enabled lazy
|
||||||
|
@value{GDBN} will attempt to defer downloading entire debug info files until
|
||||||
|
necessary. @value{GDBN} may instead download individual components of the
|
||||||
|
debug info files such as @code{.gdb_index}.
|
||||||
|
|
||||||
@kindex show debuginfod enabled
|
@kindex show debuginfod enabled
|
||||||
@item show debuginfod enabled
|
@item show debuginfod enabled
|
||||||
Display whether @code{debuginfod enabled} is set to @code{on}, @code{off} or
|
Display whether @code{debuginfod enabled} is set to @code{on}, @code{off},
|
||||||
@code{ask}.
|
@code{ask} or @code{lazy}.
|
||||||
|
|
||||||
@kindex set debuginfod urls
|
@kindex set debuginfod urls
|
||||||
@cindex configure debuginfod URLs
|
@cindex configure debuginfod URLs
|
||||||
|
|||||||
@@ -1609,6 +1609,19 @@ set_comp_unit (struct objfile *objfile, struct comp_unit *unit)
|
|||||||
return dwarf2_frame_bfd_data.set (abfd, unit);
|
return dwarf2_frame_bfd_data.set (abfd, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See frame.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
dwarf2_clear_frame_data (struct objfile *objfile)
|
||||||
|
{
|
||||||
|
bfd *abfd = objfile->obfd.get ();
|
||||||
|
|
||||||
|
if (gdb_bfd_requires_relocations (abfd))
|
||||||
|
dwarf2_frame_objfile_data.clear (objfile);
|
||||||
|
else
|
||||||
|
dwarf2_frame_bfd_data.clear (abfd);
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the FDE for *PC. Return a pointer to the FDE, and store the
|
/* Find the FDE for *PC. Return a pointer to the FDE, and store the
|
||||||
initial location associated with it into *PC. */
|
initial location associated with it into *PC. */
|
||||||
|
|
||||||
|
|||||||
@@ -238,6 +238,10 @@ void dwarf2_append_unwinders (struct gdbarch *gdbarch);
|
|||||||
extern const struct frame_base *
|
extern const struct frame_base *
|
||||||
dwarf2_frame_base_sniffer (frame_info_ptr this_frame);
|
dwarf2_frame_base_sniffer (frame_info_ptr this_frame);
|
||||||
|
|
||||||
|
/* Delete OBJFILEs comp_unit. */
|
||||||
|
|
||||||
|
extern void dwarf2_clear_frame_data (struct objfile * objfile);
|
||||||
|
|
||||||
/* Compute the DWARF CFA for a frame. */
|
/* Compute the DWARF CFA for a frame. */
|
||||||
|
|
||||||
CORE_ADDR dwarf2_frame_cfa (frame_info_ptr this_frame);
|
CORE_ADDR dwarf2_frame_cfa (frame_info_ptr this_frame);
|
||||||
|
|||||||
@@ -216,6 +216,33 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See index-cache.h. */
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte>
|
||||||
|
index_cache::lookup_gdb_index_debuginfod (const char *index_path,
|
||||||
|
std::unique_ptr<index_cache_resource> *resource)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/* Try to map that file. */
|
||||||
|
index_cache_resource_mmap *mmap_resource
|
||||||
|
= new index_cache_resource_mmap (index_path);
|
||||||
|
|
||||||
|
/* Hand the resource to the caller. */
|
||||||
|
resource->reset (mmap_resource);
|
||||||
|
|
||||||
|
return gdb::array_view<const gdb_byte>
|
||||||
|
((const gdb_byte *) mmap_resource->mapping.get (),
|
||||||
|
mmap_resource->mapping.size ());
|
||||||
|
}
|
||||||
|
catch (const gdb_exception_error &except)
|
||||||
|
{
|
||||||
|
warning (_("Unable to read %s: %s"), index_path, except.what ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
#else /* !HAVE_SYS_MMAN_H */
|
#else /* !HAVE_SYS_MMAN_H */
|
||||||
|
|
||||||
/* See dwarf-index-cache.h. This is a no-op on unsupported systems. */
|
/* See dwarf-index-cache.h. This is a no-op on unsupported systems. */
|
||||||
@@ -227,6 +254,12 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte>
|
||||||
|
index_cache::lookup_gdb_index_debuginfod (const char *index_path,
|
||||||
|
std::unique_ptr<index_cache_resource> *resource)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* See dwarf-index-cache.h. */
|
/* See dwarf-index-cache.h. */
|
||||||
|
|||||||
@@ -67,6 +67,19 @@ public:
|
|||||||
lookup_gdb_index (const bfd_build_id *build_id,
|
lookup_gdb_index (const bfd_build_id *build_id,
|
||||||
std::unique_ptr<index_cache_resource> *resource);
|
std::unique_ptr<index_cache_resource> *resource);
|
||||||
|
|
||||||
|
/* Look for an index file located at INDEX_PATH in the debuginfod cache.
|
||||||
|
Unlike lookup_gdb_index, this function does not exit early if the
|
||||||
|
index cache has not been enabled.
|
||||||
|
|
||||||
|
If found, return the contents as an array_view and store the underlying
|
||||||
|
resources (allocated memory, mapped file, etc) in RESOURCE. The returned
|
||||||
|
array_view is valid as long as RESOURCE is not destroyed.
|
||||||
|
|
||||||
|
If no matching index file is found, return an empty array view. */
|
||||||
|
gdb::array_view<const gdb_byte>
|
||||||
|
lookup_gdb_index_debuginfod (const char *index_path,
|
||||||
|
std::unique_ptr<index_cache_resource> *resource);
|
||||||
|
|
||||||
/* Return the number of cache hits. */
|
/* Return the number of cache hits. */
|
||||||
unsigned int n_hits () const
|
unsigned int n_hits () const
|
||||||
{ return m_n_hits; }
|
{ return m_n_hits; }
|
||||||
|
|||||||
@@ -102,50 +102,57 @@ read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf,
|
|||||||
{
|
{
|
||||||
LONGEST length = read_initial_length (abfd, buf, bytes_read);
|
LONGEST length = read_initial_length (abfd, buf, bytes_read);
|
||||||
|
|
||||||
gdb_assert (cu_header->initial_length_size == 4
|
if (cu_header != nullptr)
|
||||||
|| cu_header->initial_length_size == 8
|
{
|
||||||
|| cu_header->initial_length_size == 12);
|
gdb_assert (cu_header->initial_length_size == 4
|
||||||
|
|| cu_header->initial_length_size == 8
|
||||||
|
|| cu_header->initial_length_size == 12);
|
||||||
|
|
||||||
if (cu_header->initial_length_size != *bytes_read)
|
if (cu_header->initial_length_size != *bytes_read)
|
||||||
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
|
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
|
||||||
|
}
|
||||||
|
|
||||||
*offset_size = (*bytes_read == 4) ? 4 : 8;
|
*offset_size = (*bytes_read == 4) ? 4 : 8;
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read directory or file name entry format, starting with byte of
|
|
||||||
format count entries, ULEB128 pairs of entry formats, ULEB128 of
|
/* Like read_formatted_entries but the .debug_line and .debug_line_str
|
||||||
entries count and the entries themselves in the described entry
|
are stored in LINE_BUFP and LINE_STR_DATA. This is used for cases
|
||||||
format. */
|
where these sections are read from separate files without necessarily
|
||||||
|
having access to the entire debuginfo file they originate from. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
read_formatted_entries
|
||||||
const gdb_byte **bufp, struct line_header *lh,
|
(bfd *parent_bfd, const gdb_byte **line_bufp,
|
||||||
unsigned int offset_size,
|
const gdb::array_view<const gdb_byte> line_str_data,
|
||||||
void (*callback) (struct line_header *lh,
|
struct line_header *lh,
|
||||||
const char *name,
|
unsigned int offset_size,
|
||||||
dir_index d_index,
|
void (*callback) (struct line_header *lh,
|
||||||
unsigned int mod_time,
|
const char *name,
|
||||||
unsigned int length))
|
dir_index d_index,
|
||||||
|
unsigned int mod_time,
|
||||||
|
unsigned int length))
|
||||||
{
|
{
|
||||||
gdb_byte format_count, formati;
|
gdb_byte format_count, formati;
|
||||||
ULONGEST data_count, datai;
|
ULONGEST data_count, datai;
|
||||||
const gdb_byte *buf = *bufp;
|
const gdb_byte *buf = *line_bufp;
|
||||||
|
const gdb_byte *str_buf = line_str_data.data ();
|
||||||
const gdb_byte *format_header_data;
|
const gdb_byte *format_header_data;
|
||||||
unsigned int bytes_read;
|
unsigned int bytes_read;
|
||||||
|
|
||||||
format_count = read_1_byte (abfd, buf);
|
format_count = read_1_byte (parent_bfd, buf);
|
||||||
buf += 1;
|
buf += 1;
|
||||||
format_header_data = buf;
|
format_header_data = buf;
|
||||||
for (formati = 0; formati < format_count; formati++)
|
for (formati = 0; formati < format_count; formati++)
|
||||||
{
|
{
|
||||||
read_unsigned_leb128 (abfd, buf, &bytes_read);
|
read_unsigned_leb128 (parent_bfd, buf, &bytes_read);
|
||||||
buf += bytes_read;
|
buf += bytes_read;
|
||||||
read_unsigned_leb128 (abfd, buf, &bytes_read);
|
read_unsigned_leb128 (parent_bfd, buf, &bytes_read);
|
||||||
buf += bytes_read;
|
buf += bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_count = read_unsigned_leb128 (abfd, buf, &bytes_read);
|
data_count = read_unsigned_leb128 (parent_bfd, buf, &bytes_read);
|
||||||
buf += bytes_read;
|
buf += bytes_read;
|
||||||
for (datai = 0; datai < data_count; datai++)
|
for (datai = 0; datai < data_count; datai++)
|
||||||
{
|
{
|
||||||
@@ -154,10 +161,10 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
|||||||
|
|
||||||
for (formati = 0; formati < format_count; formati++)
|
for (formati = 0; formati < format_count; formati++)
|
||||||
{
|
{
|
||||||
ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
|
ULONGEST content_type = read_unsigned_leb128 (parent_bfd, format, &bytes_read);
|
||||||
format += bytes_read;
|
format += bytes_read;
|
||||||
|
|
||||||
ULONGEST form = read_unsigned_leb128 (abfd, format, &bytes_read);
|
ULONGEST form = read_unsigned_leb128 (parent_bfd, format, &bytes_read);
|
||||||
format += bytes_read;
|
format += bytes_read;
|
||||||
|
|
||||||
gdb::optional<const char *> string;
|
gdb::optional<const char *> string;
|
||||||
@@ -166,36 +173,48 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
|||||||
switch (form)
|
switch (form)
|
||||||
{
|
{
|
||||||
case DW_FORM_string:
|
case DW_FORM_string:
|
||||||
string.emplace (read_direct_string (abfd, buf, &bytes_read));
|
string.emplace (read_direct_string (parent_bfd, buf, &bytes_read));
|
||||||
buf += bytes_read;
|
buf += bytes_read;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_FORM_line_strp:
|
case DW_FORM_line_strp:
|
||||||
{
|
{
|
||||||
const char *str
|
if (line_str_data.empty ())
|
||||||
= per_objfile->read_line_string (buf, offset_size);
|
error (_("Dwarf Error: DW_FORM_line_strp used without " \
|
||||||
|
"required section"));
|
||||||
|
if (line_str_data.size () <= offset_size)
|
||||||
|
error (_("Dwarf Error: DW_FORM_line_strp pointing outside " \
|
||||||
|
"of section .debug_line"));
|
||||||
|
|
||||||
|
ULONGEST str_offset = read_offset (parent_bfd, buf, offset_size);
|
||||||
|
|
||||||
|
const char *str;
|
||||||
|
if (str_buf[str_offset] == '\0')
|
||||||
|
str = nullptr;
|
||||||
|
else
|
||||||
|
str = (const char *) (str_buf + str_offset);
|
||||||
string.emplace (str);
|
string.emplace (str);
|
||||||
buf += offset_size;
|
buf += offset_size;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case DW_FORM_data1:
|
case DW_FORM_data1:
|
||||||
uint.emplace (read_1_byte (abfd, buf));
|
uint.emplace (read_1_byte (parent_bfd, buf));
|
||||||
buf += 1;
|
buf += 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_FORM_data2:
|
case DW_FORM_data2:
|
||||||
uint.emplace (read_2_bytes (abfd, buf));
|
uint.emplace (read_2_bytes (parent_bfd, buf));
|
||||||
buf += 2;
|
buf += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_FORM_data4:
|
case DW_FORM_data4:
|
||||||
uint.emplace (read_4_bytes (abfd, buf));
|
uint.emplace (read_4_bytes (parent_bfd, buf));
|
||||||
buf += 4;
|
buf += 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_FORM_data8:
|
case DW_FORM_data8:
|
||||||
uint.emplace (read_8_bytes (abfd, buf));
|
uint.emplace (read_8_bytes (parent_bfd, buf));
|
||||||
buf += 8;
|
buf += 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -205,7 +224,7 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_FORM_udata:
|
case DW_FORM_udata:
|
||||||
uint.emplace (read_unsigned_leb128 (abfd, buf, &bytes_read));
|
uint.emplace (read_unsigned_leb128 (parent_bfd, buf, &bytes_read));
|
||||||
buf += bytes_read;
|
buf += bytes_read;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -248,28 +267,30 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
|||||||
callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
|
callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
*bufp = buf;
|
*line_bufp = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See line-header.h. */
|
/* See line-header.h. */
|
||||||
|
|
||||||
line_header_up
|
line_header_up
|
||||||
dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
dwarf_decode_line_header (bfd *parent_bfd,
|
||||||
dwarf2_per_objfile *per_objfile,
|
gdb::array_view<const gdb_byte> line_data,
|
||||||
struct dwarf2_section_info *section,
|
gdb::array_view<const gdb_byte> line_str_data,
|
||||||
const struct comp_unit_head *cu_header,
|
const gdb_byte **debug_line_ptr,
|
||||||
const char *comp_dir)
|
bool is_dwz,
|
||||||
|
const struct comp_unit_head *cu_header,
|
||||||
|
const char *comp_dir)
|
||||||
{
|
{
|
||||||
const gdb_byte *line_ptr;
|
const gdb_byte *line_ptr, *buf;
|
||||||
unsigned int bytes_read, offset_size;
|
unsigned int bytes_read, offset_size;
|
||||||
int i;
|
int i;
|
||||||
const char *cur_dir, *cur_file;
|
const char *cur_dir, *cur_file;
|
||||||
|
|
||||||
bfd *abfd = section->get_bfd_owner ();
|
buf = *debug_line_ptr;
|
||||||
|
|
||||||
/* Make sure that at least there's room for the total_length field.
|
/* Make sure that at least there's room for the total_length field.
|
||||||
That could be 12 bytes long, but we're just going to fudge that. */
|
That could be 12 bytes long, but we're just going to fudge that. */
|
||||||
if (to_underlying (sect_off) + 4 >= section->size)
|
if (buf + 4 >= line_data.data () + line_data.size ())
|
||||||
{
|
{
|
||||||
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -277,62 +298,65 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
|||||||
|
|
||||||
line_header_up lh (new line_header (comp_dir));
|
line_header_up lh (new line_header (comp_dir));
|
||||||
|
|
||||||
lh->sect_off = sect_off;
|
lh->sect_off = (sect_offset) (buf - line_data.data ());
|
||||||
lh->offset_in_dwz = is_dwz;
|
lh->offset_in_dwz = is_dwz;
|
||||||
|
|
||||||
line_ptr = section->buffer + to_underlying (sect_off);
|
line_ptr = buf;
|
||||||
|
|
||||||
/* Read in the header. */
|
/* Read in the header. */
|
||||||
LONGEST unit_length
|
LONGEST unit_length
|
||||||
= read_checked_initial_length_and_offset (abfd, line_ptr, cu_header,
|
= read_checked_initial_length_and_offset (parent_bfd, buf, cu_header,
|
||||||
&bytes_read, &offset_size);
|
&bytes_read, &offset_size);
|
||||||
|
|
||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
|
|
||||||
const gdb_byte *start_here = line_ptr;
|
if (line_ptr + unit_length > buf + line_data.size ())
|
||||||
|
|
||||||
if (line_ptr + unit_length > (section->buffer + section->size))
|
|
||||||
{
|
{
|
||||||
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gdb_byte *start_here = line_ptr;
|
||||||
|
|
||||||
lh->statement_program_end = start_here + unit_length;
|
lh->statement_program_end = start_here + unit_length;
|
||||||
lh->version = read_2_bytes (abfd, line_ptr);
|
lh->version = read_2_bytes (parent_bfd, line_ptr);
|
||||||
line_ptr += 2;
|
line_ptr += 2;
|
||||||
if (lh->version > 5)
|
if (lh->version > 5)
|
||||||
{
|
{
|
||||||
/* This is a version we don't understand. The format could have
|
/* This is a version we don't understand. The format could have
|
||||||
changed in ways we don't handle properly so just punt. */
|
changed in ways we don't handle properly so just punt. */
|
||||||
complaint (_("unsupported version in .debug_line section"));
|
complaint (_("unsupported version in .debug_line section"));
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (lh->version >= 5)
|
if (lh->version >= 5)
|
||||||
{
|
{
|
||||||
gdb_byte segment_selector_size;
|
gdb_byte segment_selector_size;
|
||||||
|
|
||||||
/* Skip address size. */
|
/* Skip address size. */
|
||||||
read_1_byte (abfd, line_ptr);
|
read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
|
|
||||||
segment_selector_size = read_1_byte (abfd, line_ptr);
|
segment_selector_size = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
if (segment_selector_size != 0)
|
if (segment_selector_size != 0)
|
||||||
{
|
{
|
||||||
complaint (_("unsupported segment selector size %u "
|
complaint (_("unsupported segment selector size %u "
|
||||||
"in .debug_line section"),
|
"in .debug_line section"),
|
||||||
segment_selector_size);
|
segment_selector_size);
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LONGEST header_length = read_offset (abfd, line_ptr, offset_size);
|
LONGEST header_length = read_offset (parent_bfd, line_ptr, offset_size);
|
||||||
line_ptr += offset_size;
|
line_ptr += offset_size;
|
||||||
lh->statement_program_start = line_ptr + header_length;
|
lh->statement_program_start = line_ptr + header_length;
|
||||||
lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
|
|
||||||
|
lh->minimum_instruction_length = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
|
|
||||||
if (lh->version >= 4)
|
if (lh->version >= 4)
|
||||||
{
|
{
|
||||||
lh->maximum_ops_per_instruction = read_1_byte (abfd, line_ptr);
|
lh->maximum_ops_per_instruction = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -345,41 +369,47 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
|||||||
"in `.debug_line' section"));
|
"in `.debug_line' section"));
|
||||||
}
|
}
|
||||||
|
|
||||||
lh->default_is_stmt = read_1_byte (abfd, line_ptr);
|
lh->default_is_stmt = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
lh->line_base = read_1_signed_byte (abfd, line_ptr);
|
|
||||||
|
lh->line_base = read_1_signed_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
lh->line_range = read_1_byte (abfd, line_ptr);
|
|
||||||
|
lh->line_range = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
lh->opcode_base = read_1_byte (abfd, line_ptr);
|
|
||||||
|
lh->opcode_base = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
|
|
||||||
lh->standard_opcode_lengths.reset (new unsigned char[lh->opcode_base]);
|
lh->standard_opcode_lengths.reset (new unsigned char[lh->opcode_base]);
|
||||||
|
|
||||||
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
|
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
|
||||||
for (i = 1; i < lh->opcode_base; ++i)
|
for (i = 1; i < lh->opcode_base; ++i)
|
||||||
{
|
{
|
||||||
lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
|
lh->standard_opcode_lengths[i] = read_1_byte (parent_bfd, line_ptr);
|
||||||
line_ptr += 1;
|
line_ptr += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lh->version >= 5)
|
if (lh->version >= 5)
|
||||||
{
|
{
|
||||||
/* Read directory table. */
|
/* Read directory table. */
|
||||||
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
|
read_formatted_entries
|
||||||
offset_size,
|
(parent_bfd, &line_ptr, line_str_data,
|
||||||
[] (struct line_header *header, const char *name,
|
lh.get (), offset_size,
|
||||||
dir_index d_index, unsigned int mod_time,
|
[] (struct line_header *header, const char *name,
|
||||||
unsigned int length)
|
dir_index d_index, unsigned int mod_time,
|
||||||
|
unsigned int length)
|
||||||
{
|
{
|
||||||
header->add_include_dir (name);
|
header->add_include_dir (name);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Read file name table. */
|
/* Read file name table. */
|
||||||
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
|
read_formatted_entries
|
||||||
offset_size,
|
(parent_bfd, &line_ptr, line_str_data,
|
||||||
[] (struct line_header *header, const char *name,
|
lh.get (), offset_size,
|
||||||
dir_index d_index, unsigned int mod_time,
|
[] (struct line_header *header, const char *name,
|
||||||
unsigned int length)
|
dir_index d_index, unsigned int mod_time,
|
||||||
|
unsigned int length)
|
||||||
{
|
{
|
||||||
header->add_file_name (name, d_index, mod_time, length);
|
header->add_file_name (name, d_index, mod_time, length);
|
||||||
});
|
});
|
||||||
@@ -387,7 +417,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Read directory table. */
|
/* Read directory table. */
|
||||||
while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
|
while ((cur_dir = read_direct_string (parent_bfd, line_ptr, &bytes_read)) != nullptr)
|
||||||
{
|
{
|
||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
lh->add_include_dir (cur_dir);
|
lh->add_include_dir (cur_dir);
|
||||||
@@ -395,17 +425,17 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
|||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
|
|
||||||
/* Read file name table. */
|
/* Read file name table. */
|
||||||
while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
|
while ((cur_file = read_direct_string (parent_bfd, line_ptr, &bytes_read)) != nullptr)
|
||||||
{
|
{
|
||||||
unsigned int mod_time, length;
|
unsigned int mod_time, length;
|
||||||
dir_index d_index;
|
dir_index d_index;
|
||||||
|
|
||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
d_index = (dir_index) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
d_index = (dir_index) read_unsigned_leb128 (parent_bfd, line_ptr, &bytes_read);
|
||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
mod_time = read_unsigned_leb128 (parent_bfd, line_ptr, &bytes_read);
|
||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
length = read_unsigned_leb128 (parent_bfd, line_ptr, &bytes_read);
|
||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
|
|
||||||
lh->add_file_name (cur_file, d_index, mod_time, length);
|
lh->add_file_name (cur_file, d_index, mod_time, length);
|
||||||
@@ -413,9 +443,40 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
|||||||
line_ptr += bytes_read;
|
line_ptr += bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_ptr > (section->buffer + section->size))
|
if (line_ptr > (buf + line_data.size ()))
|
||||||
complaint (_("line number info header doesn't "
|
complaint (_("line number info header doesn't "
|
||||||
"fit in `.debug_line' section"));
|
"fit in `.debug_line' section"));
|
||||||
|
|
||||||
|
*debug_line_ptr += unit_length + offset_size;
|
||||||
return lh;
|
return lh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line_header_up
|
||||||
|
dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||||
|
dwarf2_per_objfile *per_objfile,
|
||||||
|
struct dwarf2_section_info *section,
|
||||||
|
const struct comp_unit_head *cu_header,
|
||||||
|
const char *comp_dir)
|
||||||
|
{
|
||||||
|
struct objfile *objfile = per_objfile->objfile;
|
||||||
|
struct dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
||||||
|
|
||||||
|
/* Read .debug_line. */
|
||||||
|
dwarf2_section_info *line_sec = &per_bfd->line;
|
||||||
|
bfd_size_type line_size = line_sec->get_size (objfile);
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte> line (line_sec->buffer, line_size);
|
||||||
|
|
||||||
|
/* Read .debug_line_str. */
|
||||||
|
dwarf2_section_info *line_str_sec = &per_bfd->line_str;
|
||||||
|
bfd_size_type line_str_size = line_str_sec->get_size (objfile);
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte> line_str (line_str_sec->buffer,
|
||||||
|
line_str_size);
|
||||||
|
|
||||||
|
const gdb_byte *line_ptr = line.data () + to_underlying (sect_off);
|
||||||
|
|
||||||
|
return dwarf_decode_line_header
|
||||||
|
(per_bfd->obfd, line, line_str, &line_ptr,
|
||||||
|
is_dwz, cu_header, comp_dir);
|
||||||
|
}
|
||||||
|
|||||||
@@ -217,4 +217,14 @@ extern line_header_up dwarf_decode_line_header
|
|||||||
struct dwarf2_section_info *section, const struct comp_unit_head *cu_header,
|
struct dwarf2_section_info *section, const struct comp_unit_head *cu_header,
|
||||||
const char *comp_dir);
|
const char *comp_dir);
|
||||||
|
|
||||||
|
/* Like above but the .debug_line and .debug_line_str are stored in
|
||||||
|
LINE_DATA and LINE_STR_DATA. *DEBUG_LINE_PTR should point to a
|
||||||
|
statement program header within LINE_DATA. */
|
||||||
|
|
||||||
|
extern line_header_up dwarf_decode_line_header
|
||||||
|
(bfd *parent_bfd, gdb::array_view<const gdb_byte> line_data,
|
||||||
|
gdb::array_view<const gdb_byte> line_str_data,
|
||||||
|
const gdb_byte **debug_line_ptr, bool is_dwz,
|
||||||
|
const comp_unit_head *cu_header, const char *comp_dir);
|
||||||
|
|
||||||
#endif /* DWARF2_LINE_HEADER_H */
|
#endif /* DWARF2_LINE_HEADER_H */
|
||||||
|
|||||||
@@ -40,4 +40,11 @@ extern void dwarf2_initialize_objfile (struct objfile *objfile);
|
|||||||
|
|
||||||
extern void dwarf2_build_frame_info (struct objfile *);
|
extern void dwarf2_build_frame_info (struct objfile *);
|
||||||
|
|
||||||
|
/* Query debuginfod for the .gdb_index associated with OBJFILE. If
|
||||||
|
successful, create an objfile to hold the .gdb_index information
|
||||||
|
and act as a placeholder until the full debuginfo needs to be
|
||||||
|
downloaded. */
|
||||||
|
|
||||||
|
extern bool dwarf2_has_separate_index (struct objfile *);
|
||||||
|
|
||||||
#endif /* DWARF2_PUBLIC_H */
|
#endif /* DWARF2_PUBLIC_H */
|
||||||
|
|||||||
@@ -128,6 +128,9 @@ struct mapped_gdb_index final : public mapped_index_base
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mapped_debug_line;
|
||||||
|
typedef std::unique_ptr<mapped_debug_line> mapped_debug_line_up;
|
||||||
|
|
||||||
struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
||||||
{
|
{
|
||||||
/* This dumps minimal information about the index.
|
/* This dumps minimal information about the index.
|
||||||
@@ -136,6 +139,7 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
|||||||
gdb.dwarf2/gdb-index.exp testcase. */
|
gdb.dwarf2/gdb-index.exp testcase. */
|
||||||
void dump (struct objfile *objfile) override;
|
void dump (struct objfile *objfile) override;
|
||||||
|
|
||||||
|
/* Calls do_expand_matching_symbols and downloads debuginfo if necessary. */
|
||||||
void expand_matching_symbols
|
void expand_matching_symbols
|
||||||
(struct objfile *,
|
(struct objfile *,
|
||||||
const lookup_name_info &lookup_name,
|
const lookup_name_info &lookup_name,
|
||||||
@@ -143,6 +147,14 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
|||||||
int global,
|
int global,
|
||||||
symbol_compare_ftype *ordered_compare) override;
|
symbol_compare_ftype *ordered_compare) override;
|
||||||
|
|
||||||
|
void do_expand_matching_symbols
|
||||||
|
(struct objfile *,
|
||||||
|
const lookup_name_info &lookup_name,
|
||||||
|
domain_enum domain,
|
||||||
|
int global,
|
||||||
|
symbol_compare_ftype *ordered_compare);
|
||||||
|
|
||||||
|
/* Calls do_expand_symtabs_matching and downloads debuginfo if necessary. */
|
||||||
bool expand_symtabs_matching
|
bool expand_symtabs_matching
|
||||||
(struct objfile *objfile,
|
(struct objfile *objfile,
|
||||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||||
@@ -152,8 +164,68 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
|||||||
block_search_flags search_flags,
|
block_search_flags search_flags,
|
||||||
domain_enum domain,
|
domain_enum domain,
|
||||||
enum search_domain kind) override;
|
enum search_domain kind) override;
|
||||||
|
|
||||||
|
bool do_expand_symtabs_matching
|
||||||
|
(struct objfile *objfile,
|
||||||
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||||
|
const lookup_name_info *lookup_name,
|
||||||
|
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
|
||||||
|
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
||||||
|
block_search_flags search_flags,
|
||||||
|
domain_enum domain,
|
||||||
|
enum search_domain kind);
|
||||||
|
|
||||||
|
/* Calls dwarf2_base_index_functions::expand_all_symtabs and downloads
|
||||||
|
debuginfo if necessary. */
|
||||||
|
void expand_all_symtabs (struct objfile *objfile) override;
|
||||||
|
|
||||||
|
/* Calls dwarf2_base_index_functions::find_last_source_symtab and downloads
|
||||||
|
debuginfo if necessary. */
|
||||||
|
struct symtab *find_last_source_symtab (struct objfile *objfile) override;
|
||||||
|
|
||||||
|
/* Filename information related to this .gdb_index. */
|
||||||
|
mapped_debug_line_up mdl;
|
||||||
|
|
||||||
|
/* Return true if any of the filenames in this .gdb_index's .debug_line
|
||||||
|
mapping match FILE_MATCHER. Initializes the mapping if necessary. */
|
||||||
|
bool filename_in_debug_line
|
||||||
|
(objfile *objfile,
|
||||||
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
dwarf2_gdb_index::expand_all_symtabs (struct objfile *objfile)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dwarf2_base_index_functions::expand_all_symtabs (objfile);
|
||||||
|
}
|
||||||
|
catch (gdb_exception e)
|
||||||
|
{
|
||||||
|
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||||
|
exception_print (gdb_stderr, e);
|
||||||
|
else
|
||||||
|
read_full_dwarf_from_debuginfod (objfile, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct symtab *
|
||||||
|
dwarf2_gdb_index::find_last_source_symtab (struct objfile *objfile)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return dwarf2_base_index_functions::find_last_source_symtab (objfile);
|
||||||
|
}
|
||||||
|
catch (gdb_exception e)
|
||||||
|
{
|
||||||
|
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||||
|
exception_print (gdb_stderr, e);
|
||||||
|
else
|
||||||
|
read_full_dwarf_from_debuginfod (objfile, this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* This dumps minimal information about the index.
|
/* This dumps minimal information about the index.
|
||||||
It is called via "mt print objfiles".
|
It is called via "mt print objfiles".
|
||||||
One use is to verify .gdb_index has been loaded by the
|
One use is to verify .gdb_index has been loaded by the
|
||||||
@@ -315,7 +387,7 @@ dw2_symtab_iter_next (struct dw2_symtab_iterator *iter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf2_gdb_index::expand_matching_symbols
|
dwarf2_gdb_index::do_expand_matching_symbols
|
||||||
(struct objfile *objfile,
|
(struct objfile *objfile,
|
||||||
const lookup_name_info &name, domain_enum domain,
|
const lookup_name_info &name, domain_enum domain,
|
||||||
int global,
|
int global,
|
||||||
@@ -353,6 +425,29 @@ dwarf2_gdb_index::expand_matching_symbols
|
|||||||
}, per_objfile);
|
}, per_objfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dwarf2_gdb_index::expand_matching_symbols
|
||||||
|
(struct objfile *objfile,
|
||||||
|
const lookup_name_info &lookup_name,
|
||||||
|
domain_enum domain,
|
||||||
|
int global,
|
||||||
|
symbol_compare_ftype *ordered_compare)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
do_expand_matching_symbols (objfile, lookup_name, domain,
|
||||||
|
global, ordered_compare);
|
||||||
|
}
|
||||||
|
catch (gdb_exception e)
|
||||||
|
{
|
||||||
|
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||||
|
exception_print (gdb_stderr, e);
|
||||||
|
else
|
||||||
|
read_full_dwarf_from_debuginfod (objfile, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper for dw2_expand_matching symtabs. Called on each symbol
|
/* Helper for dw2_expand_matching symtabs. Called on each symbol
|
||||||
matched, to expand corresponding CUs that were marked. IDX is the
|
matched, to expand corresponding CUs that were marked. IDX is the
|
||||||
index of the symbol name that matched. */
|
index of the symbol name that matched. */
|
||||||
@@ -455,7 +550,7 @@ dw2_expand_marked_cus
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
dwarf2_gdb_index::expand_symtabs_matching
|
dwarf2_gdb_index::do_expand_symtabs_matching
|
||||||
(struct objfile *objfile,
|
(struct objfile *objfile,
|
||||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||||
const lookup_name_info *lookup_name,
|
const lookup_name_info *lookup_name,
|
||||||
@@ -504,6 +599,54 @@ dwarf2_gdb_index::expand_symtabs_matching
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
dwarf2_gdb_index::filename_in_debug_line
|
||||||
|
(objfile *objfile,
|
||||||
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
|
||||||
|
{
|
||||||
|
if (mdl == nullptr)
|
||||||
|
mdl.reset (new mapped_debug_line (objfile));
|
||||||
|
|
||||||
|
return mdl->contains_matching_filename (file_matcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
dwarf2_gdb_index::expand_symtabs_matching
|
||||||
|
(struct objfile *objfile,
|
||||||
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||||
|
const lookup_name_info *lookup_name,
|
||||||
|
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
|
||||||
|
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
||||||
|
block_search_flags search_flags,
|
||||||
|
domain_enum domain,
|
||||||
|
enum search_domain kind)
|
||||||
|
{
|
||||||
|
if (objfile->flags & OBJF_READNEVER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return do_expand_symtabs_matching (objfile, file_matcher, lookup_name,
|
||||||
|
symbol_matcher, expansion_notify,
|
||||||
|
search_flags, domain, kind);
|
||||||
|
}
|
||||||
|
catch (gdb_exception e)
|
||||||
|
{
|
||||||
|
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||||
|
{
|
||||||
|
exception_print (gdb_stderr, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_matcher != nullptr
|
||||||
|
&& !filename_in_debug_line (objfile, file_matcher))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
read_full_dwarf_from_debuginfod (objfile, this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quick_symbol_functions_up
|
quick_symbol_functions_up
|
||||||
mapped_gdb_index::make_quick_functions () const
|
mapped_gdb_index::make_quick_functions () const
|
||||||
{
|
{
|
||||||
@@ -797,28 +940,32 @@ dwarf2_read_gdb_index
|
|||||||
|
|
||||||
/* If there is a .dwz file, read it so we can get its CU list as
|
/* If there is a .dwz file, read it so we can get its CU list as
|
||||||
well. */
|
well. */
|
||||||
dwz = dwarf2_get_dwz_file (per_bfd);
|
if (get_gdb_index_contents_dwz != nullptr)
|
||||||
if (dwz != NULL)
|
|
||||||
{
|
{
|
||||||
mapped_gdb_index dwz_map;
|
mapped_gdb_index dwz_map;
|
||||||
const gdb_byte *dwz_types_ignore;
|
const gdb_byte *dwz_types_ignore;
|
||||||
offset_type dwz_types_elements_ignore;
|
offset_type dwz_types_elements_ignore;
|
||||||
|
dwz = dwarf2_get_dwz_file (per_bfd);
|
||||||
|
|
||||||
gdb::array_view<const gdb_byte> dwz_index_content
|
if (dwz != nullptr)
|
||||||
= get_gdb_index_contents_dwz (objfile, dwz);
|
|
||||||
|
|
||||||
if (dwz_index_content.empty ())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!read_gdb_index_from_buffer (bfd_get_filename (dwz->dwz_bfd.get ()),
|
|
||||||
1, dwz_index_content, &dwz_map,
|
|
||||||
&dwz_list, &dwz_list_elements,
|
|
||||||
&dwz_types_ignore,
|
|
||||||
&dwz_types_elements_ignore))
|
|
||||||
{
|
{
|
||||||
warning (_("could not read '.gdb_index' section from %s; skipping"),
|
gdb::array_view<const gdb_byte> dwz_index_content
|
||||||
bfd_get_filename (dwz->dwz_bfd.get ()));
|
= get_gdb_index_contents_dwz (objfile, dwz);
|
||||||
return 0;
|
|
||||||
|
if (dwz_index_content.empty ())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!read_gdb_index_from_buffer (bfd_get_filename
|
||||||
|
(dwz->dwz_bfd.get ()),
|
||||||
|
1, dwz_index_content, &dwz_map,
|
||||||
|
&dwz_list, &dwz_list_elements,
|
||||||
|
&dwz_types_ignore,
|
||||||
|
&dwz_types_elements_ignore))
|
||||||
|
{
|
||||||
|
warning (_("could not read '.gdb_index' section from %s; skipping"),
|
||||||
|
bfd_get_filename (dwz->dwz_bfd.get ()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "dwarf2/attribute.h"
|
#include "dwarf2/attribute.h"
|
||||||
#include "dwarf2/comp-unit-head.h"
|
#include "dwarf2/comp-unit-head.h"
|
||||||
#include "dwarf2/cu.h"
|
#include "dwarf2/cu.h"
|
||||||
|
#include "dwarf2/frame.h"
|
||||||
#include "dwarf2/index-cache.h"
|
#include "dwarf2/index-cache.h"
|
||||||
#include "dwarf2/index-common.h"
|
#include "dwarf2/index-common.h"
|
||||||
#include "dwarf2/leb.h"
|
#include "dwarf2/leb.h"
|
||||||
@@ -80,6 +81,7 @@
|
|||||||
#include "gdbsupport/gdb_optional.h"
|
#include "gdbsupport/gdb_optional.h"
|
||||||
#include "gdbsupport/underlying.h"
|
#include "gdbsupport/underlying.h"
|
||||||
#include "gdbsupport/hash_enum.h"
|
#include "gdbsupport/hash_enum.h"
|
||||||
|
#include "gdbsupport/scoped_mmap.h"
|
||||||
#include "filename-seen-cache.h"
|
#include "filename-seen-cache.h"
|
||||||
#include "producer.h"
|
#include "producer.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -95,6 +97,8 @@
|
|||||||
#include "split-name.h"
|
#include "split-name.h"
|
||||||
#include "gdbsupport/parallel-for.h"
|
#include "gdbsupport/parallel-for.h"
|
||||||
#include "gdbsupport/thread-pool.h"
|
#include "gdbsupport/thread-pool.h"
|
||||||
|
#include "inferior.h"
|
||||||
|
#include "debuginfod-support.h"
|
||||||
|
|
||||||
/* When == 1, print basic high level tracing messages.
|
/* When == 1, print basic high level tracing messages.
|
||||||
When > 1, be more verbose.
|
When > 1, be more verbose.
|
||||||
@@ -2112,6 +2116,170 @@ dw2_get_file_names (dwarf2_per_cu_data *this_cu,
|
|||||||
return this_cu->file_names;
|
return this_cu->file_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !HAVE_SYS_MMAN_H
|
||||||
|
|
||||||
|
bool
|
||||||
|
mapped_debug_line::contains_matching_filename
|
||||||
|
(gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte>
|
||||||
|
mapped_debug_line::read_debug_line_separate
|
||||||
|
(char *filename, std::unique_ptr<index_cache_resource> *resource)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
mapped_debug_line::read_debug_line_from_debuginfod (objfile *objfile)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !HAVE_SYS_MMAN_H */
|
||||||
|
|
||||||
|
struct line_resource_mmap final : public index_cache_resource
|
||||||
|
{
|
||||||
|
/* Try to mmap FILENAME. Throw an exception on failure, including if the
|
||||||
|
file doesn't exist. */
|
||||||
|
line_resource_mmap (const char *filename)
|
||||||
|
: mapping (mmap_file (filename))
|
||||||
|
{}
|
||||||
|
|
||||||
|
scoped_mmap mapping;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* See read.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
mapped_debug_line::contains_matching_filename
|
||||||
|
(gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
|
||||||
|
{
|
||||||
|
for (line_header_up &lh : line_headers)
|
||||||
|
for (file_entry &fe : lh->file_names ())
|
||||||
|
{
|
||||||
|
const char *filename = fe.name;
|
||||||
|
|
||||||
|
if (file_matcher (fe.name, false))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool basename_match = file_matcher (lbasename (fe.name), true);
|
||||||
|
|
||||||
|
if (!basenames_may_differ && !basename_match)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* DW_AT_comp_dir is not explicitly mentioned in the .debug_line
|
||||||
|
until DWARF5. Since we don't have access to the CU at this
|
||||||
|
point we just check for a partial match on the filename.
|
||||||
|
If there is a match, the full debuginfo will be downloaded
|
||||||
|
ane the match will be re-evalute with DW_AT_comp_dir. */
|
||||||
|
if (lh->version < 5 && fe.d_index == 0)
|
||||||
|
return basename_match;
|
||||||
|
|
||||||
|
const char *dirname = fe.include_dir (&*lh);
|
||||||
|
std::string fullname;
|
||||||
|
|
||||||
|
if (dirname == nullptr || IS_ABSOLUTE_PATH (filename))
|
||||||
|
fullname = filename;
|
||||||
|
else
|
||||||
|
fullname = std::string (dirname) + SLASH_STRING + filename;
|
||||||
|
|
||||||
|
gdb::unique_xmalloc_ptr<char> rewritten
|
||||||
|
= rewrite_source_path (fullname.c_str ());
|
||||||
|
if (rewritten != nullptr)
|
||||||
|
fullname = rewritten.release ();
|
||||||
|
|
||||||
|
if (file_matcher (fullname.c_str (), false))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See read.h. */
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte>
|
||||||
|
mapped_debug_line::read_debug_line_separate
|
||||||
|
(char *filename, std::unique_ptr<index_cache_resource> *resource)
|
||||||
|
{
|
||||||
|
if (filename == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
line_resource_mmap *mmap_resource
|
||||||
|
= new line_resource_mmap (filename);
|
||||||
|
|
||||||
|
resource->reset (mmap_resource);
|
||||||
|
|
||||||
|
return gdb::array_view<const gdb_byte>
|
||||||
|
((const gdb_byte *) mmap_resource->mapping.get (),
|
||||||
|
mmap_resource->mapping.size ());
|
||||||
|
}
|
||||||
|
catch (const gdb_exception &except)
|
||||||
|
{
|
||||||
|
exception_print (gdb_stderr, except);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See read.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
mapped_debug_line::read_debug_line_from_debuginfod (objfile *objfile)
|
||||||
|
{
|
||||||
|
const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||||
|
if (build_id == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdb::unique_xmalloc_ptr<char> line_path;
|
||||||
|
scoped_fd line_fd = debuginfod_section_query (build_id->data,
|
||||||
|
build_id->size,
|
||||||
|
bfd_get_filename
|
||||||
|
(objfile->obfd.get ()),
|
||||||
|
".debug_line",
|
||||||
|
&line_path);
|
||||||
|
|
||||||
|
if (line_fd.get () < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdb::unique_xmalloc_ptr<char> line_str_path;
|
||||||
|
scoped_fd line_str_fd = debuginfod_section_query (build_id->data,
|
||||||
|
build_id->size,
|
||||||
|
bfd_get_filename
|
||||||
|
(objfile->obfd.get ()),
|
||||||
|
".debug_line_str",
|
||||||
|
&line_str_path);
|
||||||
|
|
||||||
|
line_data = read_debug_line_separate (line_path.get (), &line_resource);
|
||||||
|
line_str_data = read_debug_line_separate (line_str_path.get (),
|
||||||
|
&line_str_resource);
|
||||||
|
|
||||||
|
const gdb_byte *line_ptr = line_data.data ();
|
||||||
|
|
||||||
|
while (line_ptr < line_data.data () + line_data.size ())
|
||||||
|
{
|
||||||
|
line_header_up lh
|
||||||
|
= dwarf_decode_line_header (objfile->obfd.get (),
|
||||||
|
line_data, line_str_data,
|
||||||
|
&line_ptr, false,
|
||||||
|
nullptr, nullptr);
|
||||||
|
line_headers.emplace_back (lh.release ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_SYS_MMAN_H */
|
||||||
|
|
||||||
|
mapped_debug_line::mapped_debug_line (objfile *objfile)
|
||||||
|
{
|
||||||
|
if (!read_debug_line_from_debuginfod (objfile))
|
||||||
|
line_headers.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
/* A helper for the "quick" functions which computes and caches the
|
/* A helper for the "quick" functions which computes and caches the
|
||||||
real path for a given file name from the line table. */
|
real path for a given file name from the line table. */
|
||||||
|
|
||||||
@@ -3168,7 +3336,7 @@ dwarf2_base_index_functions::find_per_cu (dwarf2_per_bfd *per_bfd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct compunit_symtab *
|
struct compunit_symtab *
|
||||||
dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
dwarf2_base_index_functions::do_find_pc_sect_compunit_symtab
|
||||||
(struct objfile *objfile,
|
(struct objfile *objfile,
|
||||||
struct bound_minimal_symbol msymbol,
|
struct bound_minimal_symbol msymbol,
|
||||||
CORE_ADDR pc,
|
CORE_ADDR pc,
|
||||||
@@ -3199,6 +3367,32 @@ dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct compunit_symtab *
|
||||||
|
dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
||||||
|
(struct objfile *objfile,
|
||||||
|
struct bound_minimal_symbol msymbol,
|
||||||
|
CORE_ADDR pc,
|
||||||
|
struct obj_section *section,
|
||||||
|
int warn_if_readin)
|
||||||
|
{
|
||||||
|
if (objfile->flags & OBJF_READNEVER)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return do_find_pc_sect_compunit_symtab (objfile, msymbol, pc,
|
||||||
|
section, warn_if_readin);
|
||||||
|
}
|
||||||
|
catch (gdb_exception e)
|
||||||
|
{
|
||||||
|
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
|
||||||
|
exception_print (gdb_stderr, e);
|
||||||
|
else
|
||||||
|
read_full_dwarf_from_debuginfod (objfile, this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf2_base_index_functions::map_symbol_filenames
|
dwarf2_base_index_functions::map_symbol_filenames
|
||||||
(struct objfile *objfile,
|
(struct objfile *objfile,
|
||||||
@@ -3355,6 +3549,29 @@ get_gdb_index_contents_from_cache_dwz (objfile *obj, dwz_file *dwz)
|
|||||||
return global_index_cache.lookup_gdb_index (build_id, &dwz->index_cache_res);
|
return global_index_cache.lookup_gdb_index (build_id, &dwz->index_cache_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Query debuginfod for the .gdb_index matching OBJFILE's build-id. Return the
|
||||||
|
contents if successful. */
|
||||||
|
|
||||||
|
static gdb::array_view<const gdb_byte>
|
||||||
|
get_gdb_index_contents_from_debuginfod (objfile *objfile, dwarf2_per_bfd *per_bfd)
|
||||||
|
{
|
||||||
|
const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||||
|
if (build_id == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
gdb::unique_xmalloc_ptr<char> index_path;
|
||||||
|
scoped_fd fd = debuginfod_section_query (build_id->data, build_id->size,
|
||||||
|
bfd_get_filename
|
||||||
|
(objfile->obfd.get ()),
|
||||||
|
".gdb_index",
|
||||||
|
&index_path);
|
||||||
|
if (fd.get () < 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return global_index_cache.lookup_gdb_index_debuginfod
|
||||||
|
(index_path.get (), &per_bfd->index_cache_res);
|
||||||
|
}
|
||||||
|
|
||||||
static quick_symbol_functions_up make_cooked_index_funcs ();
|
static quick_symbol_functions_up make_cooked_index_funcs ();
|
||||||
|
|
||||||
/* See dwarf2/public.h. */
|
/* See dwarf2/public.h. */
|
||||||
@@ -3420,10 +3637,106 @@ dwarf2_initialize_objfile (struct objfile *objfile)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED)
|
||||||
|
&& dwarf2_read_gdb_index (per_objfile,
|
||||||
|
get_gdb_index_contents_from_debuginfod,
|
||||||
|
nullptr))
|
||||||
|
{
|
||||||
|
dwarf_read_debug_printf ("found .gdb_index from debuginfod");
|
||||||
|
objfile->qf.push_front (per_bfd->index_table->make_quick_functions ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
global_index_cache.miss ();
|
global_index_cache.miss ();
|
||||||
objfile->qf.push_front (make_cooked_index_funcs ());
|
objfile->qf.push_front (make_cooked_index_funcs ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See read.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
read_full_dwarf_from_debuginfod (struct objfile *objfile,
|
||||||
|
dwarf2_base_index_functions *fncs)
|
||||||
|
{
|
||||||
|
gdb_assert (objfile->flags & OBJF_DOWNLOAD_DEFERRED);
|
||||||
|
|
||||||
|
const struct bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||||
|
const char *filename;
|
||||||
|
gdb_bfd_ref_ptr debug_bfd;
|
||||||
|
gdb::unique_xmalloc_ptr<char> symfile_path;
|
||||||
|
scoped_fd fd;
|
||||||
|
|
||||||
|
if (build_id == nullptr)
|
||||||
|
goto unset;
|
||||||
|
|
||||||
|
filename = bfd_get_filename (objfile->obfd.get ());
|
||||||
|
fd = debuginfod_debuginfo_query (build_id->data, build_id->size,
|
||||||
|
filename, &symfile_path);
|
||||||
|
if (fd.get () < 0)
|
||||||
|
goto unset;
|
||||||
|
|
||||||
|
/* Separate debuginfo successfully retrieved from server. */
|
||||||
|
debug_bfd = symfile_bfd_open (symfile_path.get ());
|
||||||
|
if (debug_bfd == nullptr
|
||||||
|
|| !build_id_verify (debug_bfd.get (), build_id->size, build_id->data))
|
||||||
|
{
|
||||||
|
warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
|
||||||
|
filename);
|
||||||
|
goto unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This may also trigger a dwz download. */
|
||||||
|
symbol_file_add_separate (debug_bfd, symfile_path.get (),
|
||||||
|
current_inferior ()->symfile_flags, objfile);
|
||||||
|
|
||||||
|
/* Clear frame data so it can be recalculated using DWARF. */
|
||||||
|
dwarf2_clear_frame_data (objfile);
|
||||||
|
|
||||||
|
unset:
|
||||||
|
objfile->flags &= ~OBJF_DOWNLOAD_DEFERRED;
|
||||||
|
|
||||||
|
/* Avoid reading this objfile's index from now on. If available the
|
||||||
|
separate debug objfile's index will be used instead, since it actually
|
||||||
|
contains the symbols and CUs referenced in the index. */
|
||||||
|
objfile->remove_partial_symbol (fncs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See public.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
dwarf2_has_separate_index (struct objfile *objfile)
|
||||||
|
{
|
||||||
|
if (objfile->flags & OBJF_DOWNLOAD_DEFERRED)
|
||||||
|
return true;
|
||||||
|
if (objfile->flags & OBJF_MAINLINE)
|
||||||
|
return false;
|
||||||
|
if (!IS_DIR_SEPARATOR (*objfile_filename (objfile)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdb::unique_xmalloc_ptr<char> index_path;
|
||||||
|
const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
|
||||||
|
|
||||||
|
if (build_id == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
scoped_fd fd = debuginfod_section_query (build_id->data,
|
||||||
|
build_id->size,
|
||||||
|
bfd_get_filename
|
||||||
|
(objfile->obfd.get ()),
|
||||||
|
".gdb_index",
|
||||||
|
&index_path);
|
||||||
|
|
||||||
|
if (fd.get () < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We found a separate .gdb_index file so a separate debuginfo file
|
||||||
|
should exist, but we don't want to download it until necessary.
|
||||||
|
Attach the index to this objfile and defer the debuginfo download
|
||||||
|
until gdb needs to expand symtabs referenced by the index. */
|
||||||
|
objfile->flags |= OBJF_DOWNLOAD_DEFERRED;
|
||||||
|
dwarf2_initialize_objfile (objfile);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Build a partial symbol table. */
|
/* Build a partial symbol table. */
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "gdbsupport/hash_enum.h"
|
#include "gdbsupport/hash_enum.h"
|
||||||
#include "gdbsupport/function-view.h"
|
#include "gdbsupport/function-view.h"
|
||||||
#include "gdbsupport/packed.h"
|
#include "gdbsupport/packed.h"
|
||||||
|
#include "dwarf2/line-header.h"
|
||||||
|
|
||||||
/* Hold 'maintenance (set|show) dwarf' commands. */
|
/* Hold 'maintenance (set|show) dwarf' commands. */
|
||||||
extern struct cmd_list_element *set_dwarf_cmdlist;
|
extern struct cmd_list_element *set_dwarf_cmdlist;
|
||||||
@@ -866,6 +867,10 @@ struct dwarf2_base_index_functions : public quick_symbol_functions
|
|||||||
CORE_ADDR pc, struct obj_section *section, int warn_if_readin)
|
CORE_ADDR pc, struct obj_section *section, int warn_if_readin)
|
||||||
override final;
|
override final;
|
||||||
|
|
||||||
|
struct compunit_symtab *do_find_pc_sect_compunit_symtab
|
||||||
|
(struct objfile *objfile, struct bound_minimal_symbol msymbol,
|
||||||
|
CORE_ADDR pc, struct obj_section *section, int warn_if_readin);
|
||||||
|
|
||||||
struct compunit_symtab *find_compunit_symtab_by_address
|
struct compunit_symtab *find_compunit_symtab_by_address
|
||||||
(struct objfile *objfile, CORE_ADDR address) override
|
(struct objfile *objfile, CORE_ADDR address) override
|
||||||
{
|
{
|
||||||
@@ -942,4 +947,40 @@ extern bool read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
|
|||||||
dwarf2_section_info *section,
|
dwarf2_section_info *section,
|
||||||
addrmap *mutable_map);
|
addrmap *mutable_map);
|
||||||
|
|
||||||
|
/* If OBJFILE contains information from a separately downloaded .gdb_index,
|
||||||
|
attempt to download the full debuginfo. */
|
||||||
|
|
||||||
|
extern void read_full_dwarf_from_debuginfod (struct objfile *,
|
||||||
|
dwarf2_base_index_functions *);
|
||||||
|
|
||||||
|
struct mapped_debug_line
|
||||||
|
{
|
||||||
|
mapped_debug_line (objfile *objfile);
|
||||||
|
|
||||||
|
/* Return true if any of the mapped .debug_line's filenames match
|
||||||
|
FILE_MATCHER. */
|
||||||
|
|
||||||
|
bool contains_matching_filename
|
||||||
|
(gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<line_header_up> line_headers;
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte> line_data;
|
||||||
|
gdb::array_view<const gdb_byte> line_str_data;
|
||||||
|
|
||||||
|
std::unique_ptr<index_cache_resource> line_resource;
|
||||||
|
std::unique_ptr<index_cache_resource> line_str_resource;
|
||||||
|
|
||||||
|
/* Download the .debug_line and .debug_line_str associated with OBJFILE
|
||||||
|
and populate line_headers. */
|
||||||
|
|
||||||
|
bool read_debug_line_from_debuginfod (objfile *objfile);
|
||||||
|
|
||||||
|
/* Initialize line_data and line_str_data with the .debug_line and
|
||||||
|
.debug_line_str downloaded read_debug_line_from_debuginfod. */
|
||||||
|
|
||||||
|
gdb::array_view<const gdb_byte> read_debug_line_separate
|
||||||
|
(char *filename, std::unique_ptr<index_cache_resource> *resource);
|
||||||
|
};
|
||||||
#endif /* DWARF2READ_H */
|
#endif /* DWARF2READ_H */
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ dwarf2_section_info::get_bfd_owner () const
|
|||||||
section = get_containing_section ();
|
section = get_containing_section ();
|
||||||
gdb_assert (!section->is_virtual);
|
gdb_assert (!section->is_virtual);
|
||||||
}
|
}
|
||||||
gdb_assert (section->s.section != nullptr);
|
if (section->s.section == nullptr)
|
||||||
|
error (_("Can't find owner of DWARF section."));
|
||||||
return section->s.section->owner;
|
return section->s.section->owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1242,7 +1242,7 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
|
|||||||
symbol_file_add_separate (debug_bfd, debugfile.c_str (),
|
symbol_file_add_separate (debug_bfd, debugfile.c_str (),
|
||||||
symfile_flags, objfile);
|
symfile_flags, objfile);
|
||||||
}
|
}
|
||||||
else
|
else if (!dwarf2_has_separate_index (objfile))
|
||||||
{
|
{
|
||||||
has_dwarf2 = false;
|
has_dwarf2 = false;
|
||||||
const struct bfd_build_id *build_id
|
const struct bfd_build_id *build_id
|
||||||
|
|||||||
@@ -194,6 +194,28 @@ mi_ui_out::do_redirect (ui_file *outstream)
|
|||||||
m_streams.pop_back ();
|
m_streams.pop_back ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mi_ui_out::do_redirect_to_buffer (buffer_file *buf_file)
|
||||||
|
{
|
||||||
|
if (buf_file != nullptr)
|
||||||
|
{
|
||||||
|
gdb_assert (m_streams.size () >= 1);
|
||||||
|
ui_file *stream = m_streams.back ();
|
||||||
|
|
||||||
|
string_file *sstream = dynamic_cast<string_file *>(stream);
|
||||||
|
if (sstream != nullptr)
|
||||||
|
{
|
||||||
|
buf_file->write (sstream->data (), sstream->size ());
|
||||||
|
sstream->clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_file->set_stream (stream);
|
||||||
|
m_streams.push_back (buf_file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_streams.pop_back ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mi_ui_out::field_separator ()
|
mi_ui_out::field_separator ()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ protected:
|
|||||||
virtual void do_wrap_hint (int indent) override;
|
virtual void do_wrap_hint (int indent) override;
|
||||||
virtual void do_flush () override;
|
virtual void do_flush () override;
|
||||||
virtual void do_redirect (struct ui_file *outstream) override;
|
virtual void do_redirect (struct ui_file *outstream) override;
|
||||||
|
virtual void do_redirect_to_buffer (buffer_file *buf_file) override;
|
||||||
|
|
||||||
virtual bool do_is_mi_like_p () const override
|
virtual bool do_is_mi_like_p () const override
|
||||||
{ return true; }
|
{ return true; }
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ enum objfile_flag : unsigned
|
|||||||
/* User requested that we do not read this objfile's symbolic
|
/* User requested that we do not read this objfile's symbolic
|
||||||
information. */
|
information. */
|
||||||
OBJF_READNEVER = 1 << 6,
|
OBJF_READNEVER = 1 << 6,
|
||||||
|
|
||||||
|
/* A separate .gdb_index has been downloaded for this objfile.
|
||||||
|
Debuginfo for this objfile can be downloaded when required. */
|
||||||
|
OBJF_DOWNLOAD_DEFERRED = 1 << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEF_ENUM_FLAGS_TYPE (enum objfile_flag, objfile_flags);
|
DEF_ENUM_FLAGS_TYPE (enum objfile_flag, objfile_flags);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
#include "gdb_bfd.h"
|
#include "gdb_bfd.h"
|
||||||
#include "btrace.h"
|
#include "btrace.h"
|
||||||
#include "gdbsupport/pathstuff.h"
|
#include "gdbsupport/pathstuff.h"
|
||||||
|
#include "symfile.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@@ -613,6 +613,17 @@ public:
|
|||||||
/* See quick_symbol_functions. */
|
/* See quick_symbol_functions. */
|
||||||
void require_partial_symbols (bool verbose);
|
void require_partial_symbols (bool verbose);
|
||||||
|
|
||||||
|
/* Remove TARGET from this objfile's collection of quick_symbol_functions. */
|
||||||
|
void remove_partial_symbol (quick_symbol_functions *target)
|
||||||
|
{
|
||||||
|
for (quick_symbol_functions_up &qf_up : qf)
|
||||||
|
if (qf_up.get () == target)
|
||||||
|
{
|
||||||
|
qf.remove (qf_up);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the relocation offset applied to SECTION. */
|
/* Return the relocation offset applied to SECTION. */
|
||||||
CORE_ADDR section_offset (bfd_section *section) const
|
CORE_ADDR section_offset (bfd_section *section) const
|
||||||
{
|
{
|
||||||
@@ -699,13 +710,20 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
using qf_list = std::forward_list<quick_symbol_functions_up>;
|
||||||
|
using unwrapping_qf_range = iterator_range<unwrapping_iterator<qf_list::iterator>>;
|
||||||
|
using qf_safe_range = basic_safe_range<unwrapping_qf_range>;
|
||||||
|
|
||||||
/* Ensure that partial symbols have been read and return the "quick" (aka
|
/* Ensure that partial symbols have been read and return the "quick" (aka
|
||||||
partial) symbol functions for this symbol reader. */
|
partial) symbol functions for this symbol reader. */
|
||||||
const std::forward_list<quick_symbol_functions_up> &
|
qf_safe_range
|
||||||
qf_require_partial_symbols ()
|
qf_require_partial_symbols ()
|
||||||
{
|
{
|
||||||
this->require_partial_symbols (true);
|
this->require_partial_symbols (true);
|
||||||
return qf;
|
return qf_safe_range
|
||||||
|
(unwrapping_qf_range
|
||||||
|
(unwrapping_iterator<qf_list::iterator> (qf.begin ()),
|
||||||
|
unwrapping_iterator<qf_list::iterator> (qf.end ())));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -139,19 +139,19 @@ program_space::free_all_objfiles ()
|
|||||||
|
|
||||||
void
|
void
|
||||||
program_space::add_objfile (std::unique_ptr<objfile> &&objfile,
|
program_space::add_objfile (std::unique_ptr<objfile> &&objfile,
|
||||||
struct objfile *before)
|
struct objfile *after)
|
||||||
{
|
{
|
||||||
if (before == nullptr)
|
if (after == nullptr)
|
||||||
objfiles_list.push_back (std::move (objfile));
|
objfiles_list.push_back (std::move (objfile));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto iter = std::find_if (objfiles_list.begin (), objfiles_list.end (),
|
auto iter = std::find_if (objfiles_list.begin (), objfiles_list.end (),
|
||||||
[=] (const std::unique_ptr<::objfile> &objf)
|
[=] (const std::unique_ptr<::objfile> &objf)
|
||||||
{
|
{
|
||||||
return objf.get () == before;
|
return objf.get () == after;
|
||||||
});
|
});
|
||||||
gdb_assert (iter != objfiles_list.end ());
|
gdb_assert (iter != objfiles_list.end ());
|
||||||
objfiles_list.insert (iter, std::move (objfile));
|
objfiles_list.insert (++iter, std::move (objfile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
163
gdb/progspace.h
163
gdb/progspace.h
@@ -40,56 +40,141 @@ struct address_space;
|
|||||||
struct program_space;
|
struct program_space;
|
||||||
struct so_list;
|
struct so_list;
|
||||||
|
|
||||||
typedef std::list<std::unique_ptr<objfile>> objfile_list;
|
/* An iterator that wraps an iterator over std::unique_ptr, and dereferences
|
||||||
|
the returned object. This is useful for iterating over a list of shared
|
||||||
|
pointers and returning raw pointers -- which helped avoid touching a lot
|
||||||
|
of code when changing how objfiles are managed. */
|
||||||
|
|
||||||
/* An iterator that wraps an iterator over std::unique_ptr<objfile>,
|
template<typename UniquePtrIter>
|
||||||
and dereferences the returned object. This is useful for iterating
|
class unwrapping_iterator
|
||||||
over a list of shared pointers and returning raw pointers -- which
|
|
||||||
helped avoid touching a lot of code when changing how objfiles are
|
|
||||||
managed. */
|
|
||||||
|
|
||||||
class unwrapping_objfile_iterator
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef unwrapping_iterator self_type;
|
||||||
|
typedef typename UniquePtrIter::value_type::pointer value_type;
|
||||||
|
typedef typename UniquePtrIter::reference reference;
|
||||||
|
typedef typename UniquePtrIter::pointer pointer;
|
||||||
|
typedef typename UniquePtrIter::iterator_category iterator_category;
|
||||||
|
typedef typename UniquePtrIter::difference_type difference_type;
|
||||||
|
|
||||||
typedef unwrapping_objfile_iterator self_type;
|
unwrapping_iterator (UniquePtrIter iter)
|
||||||
|
: m_iter (std::move (iter))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type operator* () const
|
||||||
|
{
|
||||||
|
return m_iter->get ();
|
||||||
|
}
|
||||||
|
|
||||||
|
unwrapping_iterator operator++ ()
|
||||||
|
{
|
||||||
|
++m_iter;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const unwrapping_iterator &other) const
|
||||||
|
{
|
||||||
|
return m_iter != other.m_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* The underlying iterator. */
|
||||||
|
UniquePtrIter m_iter;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<std::unique_ptr<objfile>> objfile_list;
|
||||||
|
|
||||||
|
/* An reverse iterator that wraps an iterator over objfile_list, and
|
||||||
|
dereferences the returned object. This is useful for reverse iterating
|
||||||
|
over a list of shared pointers and returning raw pointers -- which helped
|
||||||
|
avoid touching a lot of code when changing how objfiles are managed. */
|
||||||
|
|
||||||
|
class unwrapping_reverse_objfile_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef unwrapping_reverse_objfile_iterator self_type;
|
||||||
typedef typename ::objfile *value_type;
|
typedef typename ::objfile *value_type;
|
||||||
typedef typename ::objfile &reference;
|
typedef typename ::objfile &reference;
|
||||||
typedef typename ::objfile **pointer;
|
typedef typename ::objfile **pointer;
|
||||||
typedef typename objfile_list::iterator::iterator_category iterator_category;
|
typedef typename objfile_list::iterator::iterator_category iterator_category;
|
||||||
typedef typename objfile_list::iterator::difference_type difference_type;
|
typedef typename objfile_list::iterator::difference_type difference_type;
|
||||||
|
|
||||||
unwrapping_objfile_iterator (objfile_list::iterator iter)
|
value_type operator* () const
|
||||||
: m_iter (std::move (iter))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
objfile *operator* () const
|
|
||||||
{
|
{
|
||||||
return m_iter->get ();
|
return m_iter->get ();
|
||||||
}
|
}
|
||||||
|
|
||||||
unwrapping_objfile_iterator operator++ ()
|
unwrapping_reverse_objfile_iterator operator++ ()
|
||||||
{
|
{
|
||||||
++m_iter;
|
if (m_iter != m_begin)
|
||||||
|
--m_iter;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We can't decrement M_ITER since it is the begin iterator of the
|
||||||
|
objfile list. Set M_ITER to the list's end iterator to indicate
|
||||||
|
this is now one-past-the-end. */
|
||||||
|
m_iter = m_end;
|
||||||
|
|
||||||
|
/* Overwrite M_BEGIN to avoid possibly copying an invalid iterator. */
|
||||||
|
m_begin = m_end;
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!= (const unwrapping_objfile_iterator &other) const
|
bool operator!= (const unwrapping_reverse_objfile_iterator &other) const
|
||||||
{
|
{
|
||||||
return m_iter != other.m_iter;
|
return m_iter != other.m_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/* Return an unwrapping reverse iterator starting at the last element of
|
||||||
|
OBJF_LIST. */
|
||||||
|
static unwrapping_reverse_objfile_iterator begin (objfile_list &objf_list)
|
||||||
|
{
|
||||||
|
auto begin = objf_list.begin ();
|
||||||
|
auto end = objf_list.end ();
|
||||||
|
auto rev_begin = objf_list.end ();
|
||||||
|
|
||||||
/* The underlying iterator. */
|
/* Start REV_BEGIN on the last objfile in OBJF_LIST. */
|
||||||
objfile_list::iterator m_iter;
|
if (begin != end)
|
||||||
|
--rev_begin;
|
||||||
|
|
||||||
|
return unwrapping_reverse_objfile_iterator (rev_begin, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a one-past-the-end unwrapping reverse iterator. */
|
||||||
|
static unwrapping_reverse_objfile_iterator end (objfile_list &objf_list)
|
||||||
|
{
|
||||||
|
return unwrapping_reverse_objfile_iterator (objf_list.end (),
|
||||||
|
objf_list.end (),
|
||||||
|
objf_list.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* This begin and end methods should be used to create these objects. */
|
||||||
|
unwrapping_reverse_objfile_iterator (objfile_list::iterator iter,
|
||||||
|
objfile_list::iterator begin,
|
||||||
|
objfile_list::iterator end)
|
||||||
|
: m_iter (std::move (iter)), m_begin (std::move (begin)),
|
||||||
|
m_end (std::move (end))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The underlying iterator. */
|
||||||
|
objfile_list::iterator m_iter;
|
||||||
|
|
||||||
|
/* The underlying iterator pointing to the first objfile in the sequence. Used
|
||||||
|
to track when to stop decrementing M_ITER. */
|
||||||
|
objfile_list::iterator m_begin;
|
||||||
|
|
||||||
|
/* The underlying iterator's one-past-the-end. */
|
||||||
|
objfile_list::iterator m_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A range that returns unwrapping_iterators. */
|
||||||
|
|
||||||
/* A range that returns unwrapping_objfile_iterators. */
|
using unwrapping_objfile_range
|
||||||
|
= iterator_range<unwrapping_iterator<objfile_list::iterator>>;
|
||||||
using unwrapping_objfile_range = iterator_range<unwrapping_objfile_iterator>;
|
|
||||||
|
|
||||||
/* A program space represents a symbolic view of an address space.
|
/* A program space represents a symbolic view of an address space.
|
||||||
Roughly speaking, it holds all the data associated with a
|
Roughly speaking, it holds all the data associated with a
|
||||||
@@ -209,11 +294,12 @@ struct program_space
|
|||||||
objfiles_range objfiles ()
|
objfiles_range objfiles ()
|
||||||
{
|
{
|
||||||
return objfiles_range
|
return objfiles_range
|
||||||
(unwrapping_objfile_iterator (objfiles_list.begin ()),
|
(unwrapping_iterator<objfile_list::iterator> (objfiles_list.begin ()),
|
||||||
unwrapping_objfile_iterator (objfiles_list.end ()));
|
unwrapping_iterator<objfile_list::iterator> (objfiles_list.end ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
using objfiles_safe_range = basic_safe_range<objfiles_range>;
|
using objfiles_reverse_range = iterator_range<unwrapping_reverse_objfile_iterator>;
|
||||||
|
using objfiles_safe_reverse_range = basic_safe_range<objfiles_reverse_range>;
|
||||||
|
|
||||||
/* An iterable object that can be used to iterate over all objfiles.
|
/* An iterable object that can be used to iterate over all objfiles.
|
||||||
The basic use is in a foreach, like:
|
The basic use is in a foreach, like:
|
||||||
@@ -221,20 +307,25 @@ struct program_space
|
|||||||
for (objfile *objf : pspace->objfiles_safe ()) { ... }
|
for (objfile *objf : pspace->objfiles_safe ()) { ... }
|
||||||
|
|
||||||
This variant uses a basic_safe_iterator so that objfiles can be
|
This variant uses a basic_safe_iterator so that objfiles can be
|
||||||
deleted during iteration. */
|
deleted during iteration.
|
||||||
objfiles_safe_range objfiles_safe ()
|
|
||||||
|
The use of a reverse iterator helps ensure that separate debug
|
||||||
|
objfiles are deleted before their parent objfile. This prevents
|
||||||
|
the invalidation of an iterator due to the deletion of a parent
|
||||||
|
objfile. */
|
||||||
|
objfiles_safe_reverse_range objfiles_safe ()
|
||||||
{
|
{
|
||||||
return objfiles_safe_range
|
return objfiles_safe_reverse_range
|
||||||
(objfiles_range
|
(objfiles_reverse_range
|
||||||
(unwrapping_objfile_iterator (objfiles_list.begin ()),
|
(unwrapping_reverse_objfile_iterator::begin (objfiles_list),
|
||||||
unwrapping_objfile_iterator (objfiles_list.end ())));
|
unwrapping_reverse_objfile_iterator::end (objfiles_list)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add OBJFILE to the list of objfiles, putting it just before
|
/* Add OBJFILE to the list of objfiles, putting it just after
|
||||||
BEFORE. If BEFORE is nullptr, it will go at the end of the
|
AFTER. If AFTER is nullptr, it will go at the end of the
|
||||||
list. */
|
list. */
|
||||||
void add_objfile (std::unique_ptr<objfile> &&objfile,
|
void add_objfile (std::unique_ptr<objfile> &&objfile,
|
||||||
struct objfile *before);
|
struct objfile *after);
|
||||||
|
|
||||||
/* Remove OBJFILE from the list of objfiles. */
|
/* Remove OBJFILE from the list of objfiles. */
|
||||||
void remove_objfile (struct objfile *objfile);
|
void remove_objfile (struct objfile *objfile);
|
||||||
|
|||||||
38
gdb/stack.c
38
gdb/stack.c
@@ -220,7 +220,8 @@ static void print_frame_local_vars (frame_info_ptr frame,
|
|||||||
const char *regexp, const char *t_regexp,
|
const char *regexp, const char *t_regexp,
|
||||||
int num_tabs, struct ui_file *stream);
|
int num_tabs, struct ui_file *stream);
|
||||||
|
|
||||||
static void print_frame (const frame_print_options &opts,
|
static void print_frame (struct ui_out *uiout,
|
||||||
|
const frame_print_options &opts,
|
||||||
frame_info_ptr frame, int print_level,
|
frame_info_ptr frame, int print_level,
|
||||||
enum print_what print_what, int print_args,
|
enum print_what print_what, int print_args,
|
||||||
struct symtab_and_line sal);
|
struct symtab_and_line sal);
|
||||||
@@ -1020,16 +1021,15 @@ get_user_print_what_frame_info (gdb::optional<enum print_what> *what)
|
|||||||
Used in "where" output, and to emit breakpoint or step
|
Used in "where" output, and to emit breakpoint or step
|
||||||
messages. */
|
messages. */
|
||||||
|
|
||||||
void
|
static void
|
||||||
print_frame_info (const frame_print_options &fp_opts,
|
do_print_frame_info (struct ui_out *uiout, const frame_print_options &fp_opts,
|
||||||
frame_info_ptr frame, int print_level,
|
frame_info_ptr frame, int print_level,
|
||||||
enum print_what print_what, int print_args,
|
enum print_what print_what, int print_args,
|
||||||
int set_current_sal)
|
int set_current_sal)
|
||||||
{
|
{
|
||||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||||
int source_print;
|
int source_print;
|
||||||
int location_print;
|
int location_print;
|
||||||
struct ui_out *uiout = current_uiout;
|
|
||||||
|
|
||||||
if (!current_uiout->is_mi_like_p ()
|
if (!current_uiout->is_mi_like_p ()
|
||||||
&& fp_opts.print_frame_info != print_frame_info_auto)
|
&& fp_opts.print_frame_info != print_frame_info_auto)
|
||||||
@@ -1105,7 +1105,8 @@ print_frame_info (const frame_print_options &fp_opts,
|
|||||||
|| print_what == LOC_AND_ADDRESS
|
|| print_what == LOC_AND_ADDRESS
|
||||||
|| print_what == SHORT_LOCATION);
|
|| print_what == SHORT_LOCATION);
|
||||||
if (location_print || !sal.symtab)
|
if (location_print || !sal.symtab)
|
||||||
print_frame (fp_opts, frame, print_level, print_what, print_args, sal);
|
print_frame (uiout, fp_opts, frame, print_level,
|
||||||
|
print_what, print_args, sal);
|
||||||
|
|
||||||
source_print = (print_what == SRC_LINE || print_what == SRC_AND_LOC);
|
source_print = (print_what == SRC_LINE || print_what == SRC_AND_LOC);
|
||||||
|
|
||||||
@@ -1185,6 +1186,23 @@ print_frame_info (const frame_print_options &fp_opts,
|
|||||||
gdb_flush (gdb_stdout);
|
gdb_flush (gdb_stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Redirect output to a temporary buffer for the duration
|
||||||
|
of do_print_frame_info. */
|
||||||
|
|
||||||
|
void
|
||||||
|
print_frame_info (const frame_print_options &fp_opts,
|
||||||
|
frame_info_ptr frame, int print_level,
|
||||||
|
enum print_what print_what, int print_args,
|
||||||
|
int set_current_sal)
|
||||||
|
{
|
||||||
|
using ftype = void (ui_out *, const frame_print_options &, frame_info_ptr,
|
||||||
|
int, enum print_what, int, int);
|
||||||
|
|
||||||
|
do_with_buffered_output<ftype> (do_print_frame_info, current_uiout,
|
||||||
|
fp_opts, frame, print_level, print_what,
|
||||||
|
print_args, set_current_sal);
|
||||||
|
}
|
||||||
|
|
||||||
/* See stack.h. */
|
/* See stack.h. */
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1309,13 +1327,13 @@ find_frame_funname (frame_info_ptr frame, enum language *funlang,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_frame (const frame_print_options &fp_opts,
|
print_frame (struct ui_out *uiout,
|
||||||
|
const frame_print_options &fp_opts,
|
||||||
frame_info_ptr frame, int print_level,
|
frame_info_ptr frame, int print_level,
|
||||||
enum print_what print_what, int print_args,
|
enum print_what print_what, int print_args,
|
||||||
struct symtab_and_line sal)
|
struct symtab_and_line sal)
|
||||||
{
|
{
|
||||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||||
struct ui_out *uiout = current_uiout;
|
|
||||||
enum language funlang = language_unknown;
|
enum language funlang = language_unknown;
|
||||||
struct value_print_options opts;
|
struct value_print_options opts;
|
||||||
struct symbol *func;
|
struct symbol *func;
|
||||||
|
|||||||
@@ -109,9 +109,9 @@ objfile::has_unexpanded_symtabs ()
|
|||||||
objfile_debug_name (this));
|
objfile_debug_name (this));
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
if (iter->has_unexpanded_symtabs (this))
|
if (qf->has_unexpanded_symtabs (this))
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
@@ -134,9 +134,9 @@ objfile::find_last_source_symtab ()
|
|||||||
gdb_printf (gdb_stdlog, "qf->find_last_source_symtab (%s)\n",
|
gdb_printf (gdb_stdlog, "qf->find_last_source_symtab (%s)\n",
|
||||||
objfile_debug_name (this));
|
objfile_debug_name (this));
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
retval = iter->find_last_source_symtab (this);
|
retval = qf->find_last_source_symtab (this);
|
||||||
if (retval != nullptr)
|
if (retval != nullptr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -167,8 +167,8 @@ objfile::forget_cached_source_info ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->forget_cached_source_info (this);
|
qf->forget_cached_source_info (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -214,17 +214,17 @@ objfile::map_symtabs_matching_filename
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
if (!iter->expand_symtabs_matching (this,
|
if (!qf->expand_symtabs_matching (this,
|
||||||
match_one_filename,
|
match_one_filename,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
on_expansion,
|
on_expansion,
|
||||||
(SEARCH_GLOBAL_BLOCK
|
(SEARCH_GLOBAL_BLOCK
|
||||||
| SEARCH_STATIC_BLOCK),
|
| SEARCH_STATIC_BLOCK),
|
||||||
UNDEF_DOMAIN,
|
UNDEF_DOMAIN,
|
||||||
ALL_DOMAIN))
|
ALL_DOMAIN))
|
||||||
{
|
{
|
||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
@@ -283,18 +283,18 @@ objfile::lookup_symbol (block_enum kind, const char *name, domain_enum domain)
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
if (!iter->expand_symtabs_matching (this,
|
if (!qf->expand_symtabs_matching (this,
|
||||||
nullptr,
|
nullptr,
|
||||||
&lookup_name,
|
&lookup_name,
|
||||||
nullptr,
|
nullptr,
|
||||||
search_one_symtab,
|
search_one_symtab,
|
||||||
kind == GLOBAL_BLOCK
|
kind == GLOBAL_BLOCK
|
||||||
? SEARCH_GLOBAL_BLOCK
|
? SEARCH_GLOBAL_BLOCK
|
||||||
: SEARCH_STATIC_BLOCK,
|
: SEARCH_STATIC_BLOCK,
|
||||||
domain,
|
domain,
|
||||||
ALL_DOMAIN))
|
ALL_DOMAIN))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,8 +314,8 @@ objfile::print_stats (bool print_bcache)
|
|||||||
gdb_printf (gdb_stdlog, "qf->print_stats (%s, %d)\n",
|
gdb_printf (gdb_stdlog, "qf->print_stats (%s, %d)\n",
|
||||||
objfile_debug_name (this), print_bcache);
|
objfile_debug_name (this), print_bcache);
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->print_stats (this, print_bcache);
|
qf->print_stats (this, print_bcache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -340,16 +340,16 @@ objfile::expand_symtabs_for_function (const char *func_name)
|
|||||||
lookup_name_info base_lookup (func_name, symbol_name_match_type::FULL);
|
lookup_name_info base_lookup (func_name, symbol_name_match_type::FULL);
|
||||||
lookup_name_info lookup_name = base_lookup.make_ignore_params ();
|
lookup_name_info lookup_name = base_lookup.make_ignore_params ();
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->expand_symtabs_matching (this,
|
qf->expand_symtabs_matching (this,
|
||||||
nullptr,
|
nullptr,
|
||||||
&lookup_name,
|
&lookup_name,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
(SEARCH_GLOBAL_BLOCK
|
(SEARCH_GLOBAL_BLOCK
|
||||||
| SEARCH_STATIC_BLOCK),
|
| SEARCH_STATIC_BLOCK),
|
||||||
VAR_DOMAIN,
|
VAR_DOMAIN,
|
||||||
ALL_DOMAIN);
|
ALL_DOMAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -359,8 +359,8 @@ objfile::expand_all_symtabs ()
|
|||||||
gdb_printf (gdb_stdlog, "qf->expand_all_symtabs (%s)\n",
|
gdb_printf (gdb_stdlog, "qf->expand_all_symtabs (%s)\n",
|
||||||
objfile_debug_name (this));
|
objfile_debug_name (this));
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->expand_all_symtabs (this);
|
qf->expand_all_symtabs (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -377,16 +377,16 @@ objfile::expand_symtabs_with_fullname (const char *fullname)
|
|||||||
return filename_cmp (basenames ? basename : fullname, filename) == 0;
|
return filename_cmp (basenames ? basename : fullname, filename) == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->expand_symtabs_matching (this,
|
qf->expand_symtabs_matching (this,
|
||||||
file_matcher,
|
file_matcher,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
(SEARCH_GLOBAL_BLOCK
|
(SEARCH_GLOBAL_BLOCK
|
||||||
| SEARCH_STATIC_BLOCK),
|
| SEARCH_STATIC_BLOCK),
|
||||||
UNDEF_DOMAIN,
|
UNDEF_DOMAIN,
|
||||||
ALL_DOMAIN);
|
ALL_DOMAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -402,9 +402,9 @@ objfile::expand_matching_symbols
|
|||||||
domain_name (domain), global,
|
domain_name (domain), global,
|
||||||
host_address_to_string (ordered_compare));
|
host_address_to_string (ordered_compare));
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->expand_matching_symbols (this, name, domain, global,
|
qf->expand_matching_symbols (this, name, domain, global,
|
||||||
ordered_compare);
|
ordered_compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -429,10 +429,10 @@ objfile::expand_symtabs_matching
|
|||||||
host_address_to_string (&expansion_notify),
|
host_address_to_string (&expansion_notify),
|
||||||
search_domain_name (kind));
|
search_domain_name (kind));
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
if (!iter->expand_symtabs_matching (this, file_matcher, lookup_name,
|
if (!qf->expand_symtabs_matching (this, file_matcher, lookup_name,
|
||||||
symbol_matcher, expansion_notify,
|
symbol_matcher, expansion_notify,
|
||||||
search_flags, domain, kind))
|
search_flags, domain, kind))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -454,10 +454,10 @@ objfile::find_pc_sect_compunit_symtab (struct bound_minimal_symbol msymbol,
|
|||||||
host_address_to_string (section),
|
host_address_to_string (section),
|
||||||
warn_if_readin);
|
warn_if_readin);
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
retval = iter->find_pc_sect_compunit_symtab (this, msymbol, pc, section,
|
retval = qf->find_pc_sect_compunit_symtab (this, msymbol, pc, section,
|
||||||
warn_if_readin);
|
warn_if_readin);
|
||||||
if (retval != nullptr)
|
if (retval != nullptr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -482,8 +482,8 @@ objfile::map_symbol_filenames (gdb::function_view<symbol_filename_ftype> fun,
|
|||||||
objfile_debug_name (this),
|
objfile_debug_name (this),
|
||||||
need_fullname);
|
need_fullname);
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
iter->map_symbol_filenames (this, fun, need_fullname);
|
qf->map_symbol_filenames (this, fun, need_fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct compunit_symtab *
|
struct compunit_symtab *
|
||||||
@@ -496,9 +496,9 @@ objfile::find_compunit_symtab_by_address (CORE_ADDR address)
|
|||||||
hex_string (address));
|
hex_string (address));
|
||||||
|
|
||||||
struct compunit_symtab *result = NULL;
|
struct compunit_symtab *result = NULL;
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
result = iter->find_compunit_symtab_by_address (this, address);
|
result = qf->find_compunit_symtab_by_address (this, address);
|
||||||
if (result != nullptr)
|
if (result != nullptr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -521,10 +521,10 @@ objfile::lookup_global_symbol_language (const char *name,
|
|||||||
enum language result = language_unknown;
|
enum language result = language_unknown;
|
||||||
*symbol_found_p = false;
|
*symbol_found_p = false;
|
||||||
|
|
||||||
for (const auto &iter : qf_require_partial_symbols ())
|
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||||
{
|
{
|
||||||
result = iter->lookup_global_symbol_language (this, name, domain,
|
result = qf->lookup_global_symbol_language (this, name, domain,
|
||||||
symbol_found_p);
|
symbol_found_p);
|
||||||
if (*symbol_found_p)
|
if (*symbol_found_p)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -991,6 +991,10 @@ syms_from_objfile (struct objfile *objfile,
|
|||||||
static void
|
static void
|
||||||
finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
|
finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
|
||||||
{
|
{
|
||||||
|
struct objfile *parent = objfile->separate_debug_objfile_backlink;
|
||||||
|
bool was_deferred
|
||||||
|
= (parent != nullptr) && (parent->flags & OBJF_DOWNLOAD_DEFERRED);
|
||||||
|
|
||||||
/* If this is the main symbol file we have to clean up all users of the
|
/* If this is the main symbol file we have to clean up all users of the
|
||||||
old main symbol file. Otherwise it is sufficient to fixup all the
|
old main symbol file. Otherwise it is sufficient to fixup all the
|
||||||
breakpoints that may have been redefined by this symbol file. */
|
breakpoints that may have been redefined by this symbol file. */
|
||||||
@@ -1001,7 +1005,8 @@ finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
|
|||||||
|
|
||||||
clear_symtab_users (add_flags);
|
clear_symtab_users (add_flags);
|
||||||
}
|
}
|
||||||
else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0)
|
else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0
|
||||||
|
&& !was_deferred)
|
||||||
{
|
{
|
||||||
breakpoint_re_set ();
|
breakpoint_re_set ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,23 @@ if { [gdb_compile "$sourcetmp" "${binfile}2" executable {debug build-id}] != ""
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set sectfile "section"
|
||||||
|
set sectsrc $srcdir/$subdir/section.c
|
||||||
|
set sectexec [standard_output_file $sectfile]
|
||||||
|
|
||||||
|
set libfile "libsection"
|
||||||
|
set libsrc $srcdir/$subdir/$libfile.c
|
||||||
|
set lib_sl [standard_output_file $libfile.sl]
|
||||||
|
|
||||||
|
set lib_opts [list debug build-id ]
|
||||||
|
set exec_opts [list debug build-id shlib=$lib_sl]
|
||||||
|
|
||||||
|
if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
|
||||||
|
|| [gdb_compile $sectsrc $sectexec executable $exec_opts] != "" } {
|
||||||
|
untested "failed to compile"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
# Write some assembly that just has a .gnu_debugaltlink section.
|
# Write some assembly that just has a .gnu_debugaltlink section.
|
||||||
# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
|
# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
|
||||||
proc write_just_debugaltlink {filename dwzname buildid} {
|
proc write_just_debugaltlink {filename dwzname buildid} {
|
||||||
@@ -94,6 +111,7 @@ proc write_dwarf_file {filename buildid {value 99}} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set corefile [standard_output_file "corefile"]
|
set corefile [standard_output_file "corefile"]
|
||||||
|
set lazy_support -1
|
||||||
|
|
||||||
# Setup the global variable DEBUGDIR as a directory containing the
|
# Setup the global variable DEBUGDIR as a directory containing the
|
||||||
# debug information for the test executable.
|
# debug information for the test executable.
|
||||||
@@ -103,6 +121,8 @@ set corefile [standard_output_file "corefile"]
|
|||||||
# running.
|
# running.
|
||||||
proc_with_prefix no_url { } {
|
proc_with_prefix no_url { } {
|
||||||
global binfile outputdir debugdir
|
global binfile outputdir debugdir
|
||||||
|
global sectexec lib_sl libfile lazy_support
|
||||||
|
global gdb_prompt
|
||||||
|
|
||||||
setenv DEBUGINFOD_URLS ""
|
setenv DEBUGINFOD_URLS ""
|
||||||
|
|
||||||
@@ -119,11 +139,18 @@ proc_with_prefix no_url { } {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if { [gdb_gnu_strip_debug $lib_sl ""] != 0} {
|
||||||
|
fail "strip shlib debuginfo"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
set debugdir [standard_output_file "debug"]
|
set debugdir [standard_output_file "debug"]
|
||||||
set debuginfo [standard_output_file "fetch_src_and_symbols.debug"]
|
set debuginfo [standard_output_file "fetch_src_and_symbols.debug"]
|
||||||
|
set debuginfo_shlib [standard_output_file $libfile.sl.debug]
|
||||||
|
|
||||||
file mkdir $debugdir
|
file mkdir $debugdir
|
||||||
file rename -force $debuginfo $debugdir
|
file rename -force $debuginfo $debugdir
|
||||||
|
file rename -force $debuginfo_shlib $debugdir
|
||||||
|
|
||||||
# Test that GDB cannot find symbols without debuginfod.
|
# Test that GDB cannot find symbols without debuginfod.
|
||||||
clean_restart $binfile
|
clean_restart $binfile
|
||||||
@@ -171,6 +198,25 @@ proc_with_prefix no_url { } {
|
|||||||
|
|
||||||
clean_restart
|
clean_restart
|
||||||
gdb_test "core $::corefile" ".*in ?? ().*" "file [file tail $::corefile]"
|
gdb_test "core $::corefile" ".*in ?? ().*" "file [file tail $::corefile]"
|
||||||
|
clean_restart
|
||||||
|
|
||||||
|
# Check for lazy downloading support.
|
||||||
|
gdb_test_multiple "set debuginfod enabled lazy" "check for lazy" {
|
||||||
|
-re ".*lazy downloading is not compiled into GDB.*\n.*${gdb_prompt} $" {
|
||||||
|
set lazy_support 0
|
||||||
|
}
|
||||||
|
-re ".*${gdb_prompt} $" {
|
||||||
|
set lazy_support 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$lazy_support == 1} {
|
||||||
|
gdb_test "file $sectexec" "" "file [file tail $sectexec] file no url"
|
||||||
|
gdb_test "start" "" "file [file tail $sectexec] start no url"
|
||||||
|
gdb_test "info sharedlibrary" ".*Yes \\(\\*\\).*libsection.*" "lib no debug"
|
||||||
|
} else {
|
||||||
|
untested "lazy support no_url"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Test that GDB prints the debuginfod URLs when loading files. URLS
|
# Test that GDB prints the debuginfod URLs when loading files. URLS
|
||||||
@@ -208,6 +254,7 @@ proc disable_delete_breakpoints {} {
|
|||||||
# expected debug information.
|
# expected debug information.
|
||||||
proc_with_prefix local_url { } {
|
proc_with_prefix local_url { } {
|
||||||
global binfile outputdir debugdir db
|
global binfile outputdir debugdir db
|
||||||
|
global sectexec lib_sl libfile lazy_support
|
||||||
|
|
||||||
set url [start_debuginfod $db $debugdir]
|
set url [start_debuginfod $db $debugdir]
|
||||||
if { $url == "" } {
|
if { $url == "" } {
|
||||||
@@ -256,6 +303,17 @@ proc_with_prefix local_url { } {
|
|||||||
"file [file tail ${binfile}_alt.o]" \
|
"file [file tail ${binfile}_alt.o]" \
|
||||||
$enable_debuginfod_question "y"
|
$enable_debuginfod_question "y"
|
||||||
|
|
||||||
|
if {$lazy_support == 1} {
|
||||||
|
# GDB should now download .gdb_index.
|
||||||
|
clean_restart
|
||||||
|
gdb_test "set debuginfod enabled lazy" "" "set lazy urls"
|
||||||
|
gdb_test "file $sectexec" "" "file [file tail $sectexec] file urls"
|
||||||
|
set res ".*Download.*\.gdb_index.*libsection.*\r\nDownload.*debug info.*libsection.*"
|
||||||
|
gdb_test "start $sectexec" $res "file [file tail $sectexec] start urls"
|
||||||
|
} else {
|
||||||
|
untested "lazy support urls"
|
||||||
|
}
|
||||||
|
|
||||||
# Configure debuginfod with commands.
|
# Configure debuginfod with commands.
|
||||||
unsetenv DEBUGINFOD_URLS
|
unsetenv DEBUGINFOD_URLS
|
||||||
clean_restart
|
clean_restart
|
||||||
|
|||||||
24
gdb/testsuite/gdb.debuginfod/libsection.c
Normal file
24
gdb/testsuite/gdb.debuginfod/libsection.c
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/* This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright 2020-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
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 <stdio.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
libsection_test ()
|
||||||
|
{
|
||||||
|
printf ("In libsection\n");
|
||||||
|
}
|
||||||
28
gdb/testsuite/gdb.debuginfod/section.c
Normal file
28
gdb/testsuite/gdb.debuginfod/section.c
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright 2020-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
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 <fcntl.h>
|
||||||
|
|
||||||
|
extern void libsection_test ();
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
(void) open ("", 0);
|
||||||
|
libsection_test ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -135,7 +135,7 @@ gdb_test "p main" "= {<text variable, no debug info>} $hex <main>" \
|
|||||||
gdb_py_test_silent_cmd "python objfile.add_separate_debug_file(\"${binfile}\")" \
|
gdb_py_test_silent_cmd "python objfile.add_separate_debug_file(\"${binfile}\")" \
|
||||||
"Add separate debug file file" 1
|
"Add separate debug file file" 1
|
||||||
|
|
||||||
gdb_py_test_silent_cmd "python sep_objfile = gdb.objfiles()\[0\]" \
|
gdb_py_test_silent_cmd "python sep_objfile = gdb.objfiles()\[1\]" \
|
||||||
"Get separate debug info objfile" 1
|
"Get separate debug info objfile" 1
|
||||||
|
|
||||||
gdb_test "python print (sep_objfile.owner.filename)" "${testfile}2" \
|
gdb_test "python print (sep_objfile.owner.filename)" "${testfile}2" \
|
||||||
|
|||||||
174
gdb/thread.c
174
gdb/thread.c
@@ -1012,6 +1012,106 @@ thread_target_id_str (thread_info *tp)
|
|||||||
return target_id;
|
return target_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print thread TP. GLOBAL_IDS indicates whether REQUESTED_THREADS
|
||||||
|
is a list of global or per-inferior thread ids. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_print_thread (ui_out *uiout, const char *requested_threads,
|
||||||
|
int global_ids, int pid, int show_global_ids,
|
||||||
|
int default_inf_num, thread_info *tp,
|
||||||
|
thread_info *current_thread)
|
||||||
|
{
|
||||||
|
int core;
|
||||||
|
|
||||||
|
if (!should_print_thread (requested_threads, default_inf_num,
|
||||||
|
global_ids, pid, tp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ui_out_emit_tuple tuple_emitter (uiout, NULL);
|
||||||
|
|
||||||
|
if (!uiout->is_mi_like_p ())
|
||||||
|
{
|
||||||
|
if (tp == current_thread)
|
||||||
|
uiout->field_string ("current", "*");
|
||||||
|
else
|
||||||
|
uiout->field_skip ("current");
|
||||||
|
|
||||||
|
uiout->field_string ("id-in-tg", print_thread_id (tp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_global_ids || uiout->is_mi_like_p ())
|
||||||
|
uiout->field_signed ("id", tp->global_num);
|
||||||
|
|
||||||
|
/* Switch to the thread (and inferior / target). */
|
||||||
|
switch_to_thread (tp);
|
||||||
|
|
||||||
|
/* For the CLI, we stuff everything into the target-id field.
|
||||||
|
This is a gross hack to make the output come out looking
|
||||||
|
correct. The underlying problem here is that ui-out has no
|
||||||
|
way to specify that a field's space allocation should be
|
||||||
|
shared by several fields. For MI, we do the right thing
|
||||||
|
instead. */
|
||||||
|
|
||||||
|
if (uiout->is_mi_like_p ())
|
||||||
|
{
|
||||||
|
uiout->field_string ("target-id", target_pid_to_str (tp->ptid));
|
||||||
|
|
||||||
|
const char *extra_info = target_extra_thread_info (tp);
|
||||||
|
if (extra_info != nullptr)
|
||||||
|
uiout->field_string ("details", extra_info);
|
||||||
|
|
||||||
|
const char *name = thread_name (tp);
|
||||||
|
if (name != NULL)
|
||||||
|
uiout->field_string ("name", name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uiout->field_string ("target-id", thread_target_id_str (tp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->state == THREAD_RUNNING)
|
||||||
|
uiout->text ("(running)\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The switch above put us at the top of the stack (leaf
|
||||||
|
frame). */
|
||||||
|
print_stack_frame (get_selected_frame (NULL),
|
||||||
|
/* For MI output, print frame level. */
|
||||||
|
uiout->is_mi_like_p (),
|
||||||
|
LOCATION, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiout->is_mi_like_p ())
|
||||||
|
{
|
||||||
|
const char *state = "stopped";
|
||||||
|
|
||||||
|
if (tp->state == THREAD_RUNNING)
|
||||||
|
state = "running";
|
||||||
|
uiout->field_string ("state", state);
|
||||||
|
}
|
||||||
|
|
||||||
|
core = target_core_of_thread (tp->ptid);
|
||||||
|
if (uiout->is_mi_like_p () && core != -1)
|
||||||
|
uiout->field_signed ("core", core);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Redirect output to a temporary buffer for the duration
|
||||||
|
of do_print_thread. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_thread (ui_out *uiout, const char *requested_threads,
|
||||||
|
int global_ids, int pid, int show_global_ids,
|
||||||
|
int default_inf_num, thread_info *tp, thread_info *current_thread)
|
||||||
|
|
||||||
|
{
|
||||||
|
using ftype = void (ui_out *, const char *, int, int, int,
|
||||||
|
int, thread_info *, thread_info *);
|
||||||
|
|
||||||
|
do_with_buffered_output<ftype>
|
||||||
|
(do_print_thread, uiout, requested_threads, global_ids, pid,
|
||||||
|
show_global_ids, default_inf_num, tp, current_thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* Like print_thread_info, but in addition, GLOBAL_IDS indicates
|
/* Like print_thread_info, but in addition, GLOBAL_IDS indicates
|
||||||
whether REQUESTED_THREADS is a list of global or per-inferior
|
whether REQUESTED_THREADS is a list of global or per-inferior
|
||||||
thread ids. */
|
thread ids. */
|
||||||
@@ -1095,82 +1195,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
|
|||||||
for (inferior *inf : all_inferiors ())
|
for (inferior *inf : all_inferiors ())
|
||||||
for (thread_info *tp : inf->threads ())
|
for (thread_info *tp : inf->threads ())
|
||||||
{
|
{
|
||||||
int core;
|
|
||||||
|
|
||||||
any_thread = true;
|
any_thread = true;
|
||||||
if (tp == current_thread && tp->state == THREAD_EXITED)
|
if (tp == current_thread && tp->state == THREAD_EXITED)
|
||||||
current_exited = true;
|
current_exited = true;
|
||||||
|
|
||||||
if (!should_print_thread (requested_threads, default_inf_num,
|
print_thread (uiout, requested_threads, global_ids, pid,
|
||||||
global_ids, pid, tp))
|
show_global_ids, default_inf_num, tp, current_thread);
|
||||||
continue;
|
|
||||||
|
|
||||||
ui_out_emit_tuple tuple_emitter (uiout, NULL);
|
|
||||||
|
|
||||||
if (!uiout->is_mi_like_p ())
|
|
||||||
{
|
|
||||||
if (tp == current_thread)
|
|
||||||
uiout->field_string ("current", "*");
|
|
||||||
else
|
|
||||||
uiout->field_skip ("current");
|
|
||||||
|
|
||||||
uiout->field_string ("id-in-tg", print_thread_id (tp));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_global_ids || uiout->is_mi_like_p ())
|
|
||||||
uiout->field_signed ("id", tp->global_num);
|
|
||||||
|
|
||||||
/* Switch to the thread (and inferior / target). */
|
|
||||||
switch_to_thread (tp);
|
|
||||||
|
|
||||||
/* For the CLI, we stuff everything into the target-id field.
|
|
||||||
This is a gross hack to make the output come out looking
|
|
||||||
correct. The underlying problem here is that ui-out has no
|
|
||||||
way to specify that a field's space allocation should be
|
|
||||||
shared by several fields. For MI, we do the right thing
|
|
||||||
instead. */
|
|
||||||
|
|
||||||
if (uiout->is_mi_like_p ())
|
|
||||||
{
|
|
||||||
uiout->field_string ("target-id", target_pid_to_str (tp->ptid));
|
|
||||||
|
|
||||||
const char *extra_info = target_extra_thread_info (tp);
|
|
||||||
if (extra_info != nullptr)
|
|
||||||
uiout->field_string ("details", extra_info);
|
|
||||||
|
|
||||||
const char *name = thread_name (tp);
|
|
||||||
if (name != NULL)
|
|
||||||
uiout->field_string ("name", name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uiout->field_string ("target-id", thread_target_id_str (tp));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tp->state == THREAD_RUNNING)
|
|
||||||
uiout->text ("(running)\n");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* The switch above put us at the top of the stack (leaf
|
|
||||||
frame). */
|
|
||||||
print_stack_frame (get_selected_frame (NULL),
|
|
||||||
/* For MI output, print frame level. */
|
|
||||||
uiout->is_mi_like_p (),
|
|
||||||
LOCATION, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uiout->is_mi_like_p ())
|
|
||||||
{
|
|
||||||
const char *state = "stopped";
|
|
||||||
|
|
||||||
if (tp->state == THREAD_RUNNING)
|
|
||||||
state = "running";
|
|
||||||
uiout->field_string ("state", state);
|
|
||||||
}
|
|
||||||
|
|
||||||
core = target_core_of_thread (tp->ptid);
|
|
||||||
if (uiout->is_mi_like_p () && core != -1)
|
|
||||||
uiout->field_signed ("core", core);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This end scope restores the current thread and the frame
|
/* This end scope restores the current thread and the frame
|
||||||
|
|||||||
@@ -234,6 +234,83 @@ string_file::can_emit_style_escape ()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* See ui-file.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
buffer_file::wrap_here (int indent)
|
||||||
|
{
|
||||||
|
m_string_wraps.emplace (m_string_wraps.end (),
|
||||||
|
string_wrap_pair (m_string, indent));
|
||||||
|
m_string.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See ui-file.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
buffer_file::flush_to_stream ()
|
||||||
|
{
|
||||||
|
if (m_stream == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Add m_string to m_string_wraps with no corresponding wrap_here. */
|
||||||
|
wrap_here (-1);
|
||||||
|
|
||||||
|
for (string_wrap_pair pair : m_string_wraps)
|
||||||
|
{
|
||||||
|
std::string buf = std::move (pair.first);
|
||||||
|
size_t size = buf.size ();
|
||||||
|
|
||||||
|
/* Write each line separately. */
|
||||||
|
for (size_t prev = 0, cur = 0; cur < size; ++cur)
|
||||||
|
if (buf.at (cur) == '\n' || cur == size - 1)
|
||||||
|
{
|
||||||
|
std::string sub = buf.substr (prev, cur - prev + 1);
|
||||||
|
m_stream->puts (sub.c_str ());
|
||||||
|
prev = cur + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.second >= 0)
|
||||||
|
m_stream->wrap_here (pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_string_wraps.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See ui-file.h. */
|
||||||
|
|
||||||
|
ui_file *
|
||||||
|
buffer_file::get_unbuffered_stream (ui_file *stream)
|
||||||
|
{
|
||||||
|
buffer_file *buf = dynamic_cast<buffer_file *> (stream);
|
||||||
|
|
||||||
|
if (buf == nullptr || buf->m_stream == nullptr)
|
||||||
|
return stream;
|
||||||
|
|
||||||
|
return get_unbuffered_stream (buf->m_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See ui-file.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
buffer_file::set_stream (ui_file *stream)
|
||||||
|
{
|
||||||
|
if (m_stream == nullptr)
|
||||||
|
m_stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See ui-file.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
buffer_file::isatty ()
|
||||||
|
{
|
||||||
|
if (m_stream != nullptr)
|
||||||
|
return m_stream->isatty ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
stdio_file::stdio_file (FILE *file, bool close_p)
|
stdio_file::stdio_file (FILE *file, bool close_p)
|
||||||
{
|
{
|
||||||
set_stream (file);
|
set_stream (file);
|
||||||
|
|||||||
@@ -220,13 +220,53 @@ public:
|
|||||||
bool empty () const { return m_string.empty (); }
|
bool empty () const { return m_string.empty (); }
|
||||||
void clear () { return m_string.clear (); }
|
void clear () { return m_string.clear (); }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
/* The internal buffer. */
|
/* The internal buffer. */
|
||||||
std::string m_string;
|
std::string m_string;
|
||||||
|
|
||||||
bool m_term_out;
|
bool m_term_out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A string_file implementation that collects output on behalf of a
|
||||||
|
given ui_file. Provides access to the underlying ui_file so
|
||||||
|
that buffering can be selectively bypassed. */
|
||||||
|
|
||||||
|
class buffer_file : public string_file
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit buffer_file (bool term_out)
|
||||||
|
: string_file (term_out), m_stream (nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* Associate STREAM with this buffer_file. */
|
||||||
|
void set_stream (ui_file *stream);
|
||||||
|
|
||||||
|
/* Record the wrap hint. When flushing the buffer, the underlying
|
||||||
|
ui_file's wrap_here will be called at the current point in the output. */
|
||||||
|
void wrap_here (int indent) override;
|
||||||
|
|
||||||
|
/* Flush collected output to the underlying ui_file. */
|
||||||
|
void flush_to_stream ();
|
||||||
|
|
||||||
|
/* Return true if the underlying stream is a tty. */
|
||||||
|
bool isatty () override;
|
||||||
|
|
||||||
|
/* Return a pointer to STREAM's underlying ui_file. Recursively called until
|
||||||
|
a non-buffer_file is found. */
|
||||||
|
static ui_file *get_unbuffered_stream (ui_file *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* The underlying output stream. */
|
||||||
|
ui_file *m_stream;
|
||||||
|
|
||||||
|
typedef std::pair<std::string, int> string_wrap_pair;
|
||||||
|
|
||||||
|
/* A collection of strings paired with an int representing the argument
|
||||||
|
to a wrap_here call. */
|
||||||
|
std::vector<string_wrap_pair> m_string_wraps;
|
||||||
|
};
|
||||||
|
|
||||||
/* A ui_file implementation that maps directly onto <stdio.h>'s FILE.
|
/* A ui_file implementation that maps directly onto <stdio.h>'s FILE.
|
||||||
A stdio_file can either own its underlying file, or not. If it
|
A stdio_file can either own its underlying file, or not. If it
|
||||||
owns the file, then destroying the stdio_file closes the underlying
|
owns the file, then destroying the stdio_file closes the underlying
|
||||||
|
|||||||
20
gdb/ui-out.c
20
gdb/ui-out.c
@@ -799,6 +799,12 @@ ui_out::redirect (ui_file *outstream)
|
|||||||
do_redirect (outstream);
|
do_redirect (outstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_out::redirect_to_buffer (buffer_file *buf_file)
|
||||||
|
{
|
||||||
|
do_redirect_to_buffer (buf_file);
|
||||||
|
}
|
||||||
|
|
||||||
/* Test the flags against the mask given. */
|
/* Test the flags against the mask given. */
|
||||||
ui_out_flags
|
ui_out_flags
|
||||||
ui_out::test_flags (ui_out_flags mask)
|
ui_out::test_flags (ui_out_flags mask)
|
||||||
@@ -871,3 +877,17 @@ ui_out::ui_out (ui_out_flags flags)
|
|||||||
ui_out::~ui_out ()
|
ui_out::~ui_out ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui_out_buffer_pop::ui_out_buffer_pop (ui_out *uiout)
|
||||||
|
: m_uiout (uiout), m_buf_file (uiout->can_emit_style_escape ()),
|
||||||
|
m_prev_gdb_stdout (gdb_stdout)
|
||||||
|
{
|
||||||
|
m_uiout->redirect_to_buffer (&m_buf_file);
|
||||||
|
gdb_stdout = &m_buf_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_out_buffer_pop::~ui_out_buffer_pop ()
|
||||||
|
{
|
||||||
|
m_uiout->redirect_to_buffer (nullptr);
|
||||||
|
gdb_stdout = m_prev_gdb_stdout;
|
||||||
|
}
|
||||||
|
|||||||
66
gdb/ui-out.h
66
gdb/ui-out.h
@@ -262,6 +262,9 @@ class ui_out
|
|||||||
/* Redirect the output of a ui_out object temporarily. */
|
/* Redirect the output of a ui_out object temporarily. */
|
||||||
void redirect (ui_file *outstream);
|
void redirect (ui_file *outstream);
|
||||||
|
|
||||||
|
/* Redirect the output of a ui_out object to a buffer_file temporarily. */
|
||||||
|
void redirect_to_buffer (buffer_file *buf_file);
|
||||||
|
|
||||||
ui_out_flags test_flags (ui_out_flags mask);
|
ui_out_flags test_flags (ui_out_flags mask);
|
||||||
|
|
||||||
/* HACK: Code in GDB is currently checking to see the type of ui_out
|
/* HACK: Code in GDB is currently checking to see the type of ui_out
|
||||||
@@ -360,6 +363,7 @@ protected:
|
|||||||
virtual void do_wrap_hint (int indent) = 0;
|
virtual void do_wrap_hint (int indent) = 0;
|
||||||
virtual void do_flush () = 0;
|
virtual void do_flush () = 0;
|
||||||
virtual void do_redirect (struct ui_file *outstream) = 0;
|
virtual void do_redirect (struct ui_file *outstream) = 0;
|
||||||
|
virtual void do_redirect_to_buffer (buffer_file *buf_file) = 0;
|
||||||
|
|
||||||
virtual void do_progress_start () = 0;
|
virtual void do_progress_start () = 0;
|
||||||
virtual void do_progress_notify (const std::string &, const char *,
|
virtual void do_progress_notify (const std::string &, const char *,
|
||||||
@@ -470,4 +474,66 @@ private:
|
|||||||
struct ui_out *m_uiout;
|
struct ui_out *m_uiout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* On construction, redirect a uiout and gdb_stdout to a buffer_file.
|
||||||
|
On destruction restore uiout and gdb_stdout. */
|
||||||
|
|
||||||
|
class ui_out_buffer_pop
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ui_out_buffer_pop (ui_out *uiout);
|
||||||
|
|
||||||
|
~ui_out_buffer_pop ();
|
||||||
|
|
||||||
|
/* Flush buffered output to the underlying output stream. */
|
||||||
|
void flush ()
|
||||||
|
{
|
||||||
|
m_buf_file.flush_to_stream ();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_out_buffer_pop (const ui_out_buffer_pop &) = delete;
|
||||||
|
ui_out_buffer_pop &operator= (const ui_out_buffer_pop &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* ui_out being temporarily redirected. */
|
||||||
|
struct ui_out *m_uiout;
|
||||||
|
|
||||||
|
/* Buffer which output is temporarily redirected to for the lifetime of
|
||||||
|
this object. */
|
||||||
|
buffer_file m_buf_file;
|
||||||
|
|
||||||
|
/* Original gdb_stdout at the time of this object's construction. */
|
||||||
|
ui_file *m_prev_gdb_stdout;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Redirect output to a buffer_file for the duration of FUNC. */
|
||||||
|
|
||||||
|
template<typename F, typename... Arg>
|
||||||
|
void
|
||||||
|
do_with_buffered_output (F func, ui_out *uiout, Arg... args)
|
||||||
|
{
|
||||||
|
ui_out_buffer_pop buf (uiout);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
func (uiout, std::forward<Arg> (args)...);
|
||||||
|
}
|
||||||
|
catch (gdb_exception &ex)
|
||||||
|
{
|
||||||
|
/* Ideally flush would be called in the destructor of buf,
|
||||||
|
however flushing might cause an exception to be thrown.
|
||||||
|
Catch it and ensure the first exception propagates. */
|
||||||
|
try
|
||||||
|
{
|
||||||
|
buf.flush ();
|
||||||
|
}
|
||||||
|
catch (const gdb_exception &ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
throw_exception (std::move (ex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try was successful. Let any further exceptions propagate. */
|
||||||
|
buf.flush ();
|
||||||
|
}
|
||||||
#endif /* UI_OUT_H */
|
#endif /* UI_OUT_H */
|
||||||
|
|||||||
@@ -60,5 +60,4 @@ struct iterator_range
|
|||||||
private:
|
private:
|
||||||
IteratorType m_begin, m_end;
|
IteratorType m_begin, m_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* GDBSUPPORT_ITERATOR_RANGE_H */
|
#endif /* GDBSUPPORT_ITERATOR_RANGE_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user