mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
6 Commits
gdb-15.1-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.])
|
||||
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 ();
|
||||
}
|
||||
|
||||
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
|
||||
cli_ui_out::do_progress_notify. */
|
||||
|
||||
@@ -299,7 +312,8 @@ cli_ui_out::do_progress_notify (const std::string &msg,
|
||||
double howmuch, double total)
|
||||
{
|
||||
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 ());
|
||||
|
||||
if (chars_per_line > MAX_CHARS_PER_LINE)
|
||||
@@ -384,7 +398,8 @@ cli_ui_out::do_progress_notify (const std::string &msg,
|
||||
void
|
||||
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 ();
|
||||
|
||||
scoped_restore save_pagination
|
||||
@@ -413,10 +428,11 @@ void
|
||||
cli_ui_out::do_progress_end ()
|
||||
{
|
||||
struct ui_file *stream = m_streams.back ();
|
||||
m_progress_info.pop_back ();
|
||||
|
||||
if (stream->isatty ())
|
||||
clear_progress_notify ();
|
||||
|
||||
m_progress_info.pop_back ();
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
|
||||
@@ -71,6 +71,7 @@ protected:
|
||||
virtual void do_wrap_hint (int indent) override;
|
||||
virtual void do_flush () 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_notify (const std::string &, const char *,
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
/* define if the compiler supports basic C++11 syntax */
|
||||
#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
|
||||
you don't. */
|
||||
#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 as well as optional section downloading support
|
||||
|
||||
# Check whether --with-debuginfod was given.
|
||||
if test "${with_debuginfod+set}" = set; then :
|
||||
@@ -18365,6 +18365,106 @@ $as_echo "$with_debuginfod" >&6; }
|
||||
|
||||
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
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.179" >&5
|
||||
$as_echo_n "checking for libdebuginfod >= 0.179... " >&6; }
|
||||
|
||||
@@ -342,7 +342,7 @@ case $host_os in
|
||||
esac
|
||||
|
||||
# Handle optional debuginfod support
|
||||
AC_DEBUGINFOD
|
||||
AC_DEBUGINFOD_SECTION
|
||||
|
||||
# Libunwind support for 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_off[] = "off";
|
||||
static const char debuginfod_ask[] = "ask";
|
||||
static const char debuginfod_lazy[] = "lazy";
|
||||
|
||||
static const char *debuginfod_enabled_enum[] =
|
||||
{
|
||||
debuginfod_on,
|
||||
debuginfod_off,
|
||||
debuginfod_ask,
|
||||
debuginfod_lazy,
|
||||
nullptr
|
||||
};
|
||||
|
||||
@@ -80,6 +82,15 @@ debuginfod_exec_query (const unsigned char *build_id,
|
||||
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.")
|
||||
|
||||
#else
|
||||
@@ -148,7 +159,8 @@ progressfn (debuginfod_client *c, long cur, long total)
|
||||
|
||||
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 ());
|
||||
return 1;
|
||||
}
|
||||
@@ -264,10 +276,14 @@ static void
|
||||
print_outcome (int fd, const char *desc, const char *fname)
|
||||
{
|
||||
if (fd < 0 && fd != -ENOENT)
|
||||
gdb_printf (_("Download failed: %s. Continuing without %s %ps.\n"),
|
||||
safe_strerror (-fd),
|
||||
desc,
|
||||
styled_string (file_name_style.style (), fname));
|
||||
{
|
||||
ui_file *outstream = buffer_file::get_unbuffered_stream (gdb_stdout);
|
||||
gdb_printf (outstream,
|
||||
_("Download failed: %s. Continuing without %s %ps.\n"),
|
||||
safe_strerror (-fd),
|
||||
desc,
|
||||
styled_string (file_name_style.style (), fname));
|
||||
}
|
||||
}
|
||||
|
||||
/* See debuginfod-support.h */
|
||||
@@ -401,6 +417,56 @@ debuginfod_exec_query (const unsigned char *build_id,
|
||||
|
||||
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
|
||||
|
||||
/* Set callback for "set debuginfod enabled". */
|
||||
@@ -409,6 +475,14 @@ static void
|
||||
set_debuginfod_enabled (const char *value)
|
||||
{
|
||||
#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;
|
||||
#else
|
||||
/* Disabling debuginfod when gdb is not built with it is a no-op. */
|
||||
@@ -508,8 +582,12 @@ _initialize_debuginfod ()
|
||||
_("Set whether to use debuginfod."),
|
||||
_("Show whether to use debuginfod."),
|
||||
_("\
|
||||
When on, enable the use of debuginfod to download missing debug info and\n\
|
||||
source files."),
|
||||
When set to \"on\", enable the use of debuginfod to download missing\n\
|
||||
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,
|
||||
get_debuginfod_enabled,
|
||||
show_debuginfod_enabled,
|
||||
|
||||
@@ -81,4 +81,28 @@ extern scoped_fd debuginfod_exec_query (const unsigned char *build_id,
|
||||
const char *filename,
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
*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 */
|
||||
|
||||
@@ -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}
|
||||
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
|
||||
@item show debuginfod enabled
|
||||
Display whether @code{debuginfod enabled} is set to @code{on}, @code{off} or
|
||||
@code{ask}.
|
||||
Display whether @code{debuginfod enabled} is set to @code{on}, @code{off},
|
||||
@code{ask} or @code{lazy}.
|
||||
|
||||
@kindex set 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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
initial location associated with it into *PC. */
|
||||
|
||||
|
||||
@@ -238,6 +238,10 @@ void dwarf2_append_unwinders (struct gdbarch *gdbarch);
|
||||
extern const struct frame_base *
|
||||
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. */
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* 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 {};
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/* See dwarf-index-cache.h. */
|
||||
|
||||
@@ -67,6 +67,19 @@ public:
|
||||
lookup_gdb_index (const bfd_build_id *build_id,
|
||||
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. */
|
||||
unsigned int n_hits () const
|
||||
{ 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);
|
||||
|
||||
gdb_assert (cu_header->initial_length_size == 4
|
||||
|| cu_header->initial_length_size == 8
|
||||
|| cu_header->initial_length_size == 12);
|
||||
if (cu_header != nullptr)
|
||||
{
|
||||
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)
|
||||
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
|
||||
if (cu_header->initial_length_size != *bytes_read)
|
||||
complaint (_("intermixed 32-bit and 64-bit DWARF sections"));
|
||||
}
|
||||
|
||||
*offset_size = (*bytes_read == 4) ? 4 : 8;
|
||||
return length;
|
||||
}
|
||||
|
||||
/* Read directory or file name entry format, starting with byte of
|
||||
format count entries, ULEB128 pairs of entry formats, ULEB128 of
|
||||
entries count and the entries themselves in the described entry
|
||||
format. */
|
||||
|
||||
/* Like read_formatted_entries but the .debug_line and .debug_line_str
|
||||
are stored in LINE_BUFP and LINE_STR_DATA. This is used for cases
|
||||
where these sections are read from separate files without necessarily
|
||||
having access to the entire debuginfo file they originate from. */
|
||||
|
||||
static void
|
||||
read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
const gdb_byte **bufp, struct line_header *lh,
|
||||
unsigned int offset_size,
|
||||
void (*callback) (struct line_header *lh,
|
||||
const char *name,
|
||||
dir_index d_index,
|
||||
unsigned int mod_time,
|
||||
unsigned int length))
|
||||
read_formatted_entries
|
||||
(bfd *parent_bfd, const gdb_byte **line_bufp,
|
||||
const gdb::array_view<const gdb_byte> line_str_data,
|
||||
struct line_header *lh,
|
||||
unsigned int offset_size,
|
||||
void (*callback) (struct line_header *lh,
|
||||
const char *name,
|
||||
dir_index d_index,
|
||||
unsigned int mod_time,
|
||||
unsigned int length))
|
||||
{
|
||||
gdb_byte format_count, formati;
|
||||
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;
|
||||
unsigned int bytes_read;
|
||||
|
||||
format_count = read_1_byte (abfd, buf);
|
||||
format_count = read_1_byte (parent_bfd, buf);
|
||||
buf += 1;
|
||||
format_header_data = buf;
|
||||
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;
|
||||
read_unsigned_leb128 (abfd, buf, &bytes_read);
|
||||
read_unsigned_leb128 (parent_bfd, 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;
|
||||
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++)
|
||||
{
|
||||
ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
|
||||
ULONGEST content_type = read_unsigned_leb128 (parent_bfd, 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;
|
||||
|
||||
gdb::optional<const char *> string;
|
||||
@@ -166,36 +173,48 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
switch (form)
|
||||
{
|
||||
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;
|
||||
break;
|
||||
|
||||
case DW_FORM_line_strp:
|
||||
{
|
||||
const char *str
|
||||
= per_objfile->read_line_string (buf, offset_size);
|
||||
if (line_str_data.empty ())
|
||||
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);
|
||||
buf += offset_size;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_FORM_data1:
|
||||
uint.emplace (read_1_byte (abfd, buf));
|
||||
uint.emplace (read_1_byte (parent_bfd, buf));
|
||||
buf += 1;
|
||||
break;
|
||||
|
||||
case DW_FORM_data2:
|
||||
uint.emplace (read_2_bytes (abfd, buf));
|
||||
uint.emplace (read_2_bytes (parent_bfd, buf));
|
||||
buf += 2;
|
||||
break;
|
||||
|
||||
case DW_FORM_data4:
|
||||
uint.emplace (read_4_bytes (abfd, buf));
|
||||
uint.emplace (read_4_bytes (parent_bfd, buf));
|
||||
buf += 4;
|
||||
break;
|
||||
|
||||
case DW_FORM_data8:
|
||||
uint.emplace (read_8_bytes (abfd, buf));
|
||||
uint.emplace (read_8_bytes (parent_bfd, buf));
|
||||
buf += 8;
|
||||
break;
|
||||
|
||||
@@ -205,7 +224,7 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
||||
break;
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
*line_bufp = buf;
|
||||
}
|
||||
|
||||
/* See line-header.h. */
|
||||
|
||||
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)
|
||||
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 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;
|
||||
int i;
|
||||
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.
|
||||
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 ();
|
||||
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));
|
||||
|
||||
lh->sect_off = sect_off;
|
||||
lh->sect_off = (sect_offset) (buf - line_data.data ());
|
||||
lh->offset_in_dwz = is_dwz;
|
||||
|
||||
line_ptr = section->buffer + to_underlying (sect_off);
|
||||
line_ptr = buf;
|
||||
|
||||
/* Read in the header. */
|
||||
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);
|
||||
|
||||
line_ptr += bytes_read;
|
||||
|
||||
const gdb_byte *start_here = line_ptr;
|
||||
|
||||
if (line_ptr + unit_length > (section->buffer + section->size))
|
||||
if (line_ptr + unit_length > buf + line_data.size ())
|
||||
{
|
||||
dwarf2_statement_list_fits_in_line_number_section_complaint ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const gdb_byte *start_here = line_ptr;
|
||||
|
||||
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;
|
||||
if (lh->version > 5)
|
||||
{
|
||||
/* This is a version we don't understand. The format could have
|
||||
changed in ways we don't handle properly so just punt. */
|
||||
complaint (_("unsupported version in .debug_line section"));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (lh->version >= 5)
|
||||
{
|
||||
gdb_byte segment_selector_size;
|
||||
|
||||
/* Skip address size. */
|
||||
read_1_byte (abfd, line_ptr);
|
||||
read_1_byte (parent_bfd, line_ptr);
|
||||
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;
|
||||
if (segment_selector_size != 0)
|
||||
{
|
||||
complaint (_("unsupported segment selector size %u "
|
||||
"in .debug_line section"),
|
||||
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;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
@@ -345,41 +369,47 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
|
||||
"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;
|
||||
lh->line_base = read_1_signed_byte (abfd, line_ptr);
|
||||
|
||||
lh->line_base = read_1_signed_byte (parent_bfd, line_ptr);
|
||||
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;
|
||||
lh->opcode_base = read_1_byte (abfd, line_ptr);
|
||||
|
||||
lh->opcode_base = read_1_byte (parent_bfd, line_ptr);
|
||||
line_ptr += 1;
|
||||
|
||||
lh->standard_opcode_lengths.reset (new unsigned char[lh->opcode_base]);
|
||||
|
||||
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
|
||||
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;
|
||||
}
|
||||
|
||||
if (lh->version >= 5)
|
||||
{
|
||||
/* Read directory table. */
|
||||
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
|
||||
offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
read_formatted_entries
|
||||
(parent_bfd, &line_ptr, line_str_data,
|
||||
lh.get (), offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
{
|
||||
header->add_include_dir (name);
|
||||
});
|
||||
|
||||
/* Read file name table. */
|
||||
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
|
||||
offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int length)
|
||||
read_formatted_entries
|
||||
(parent_bfd, &line_ptr, line_str_data,
|
||||
lh.get (), offset_size,
|
||||
[] (struct line_header *header, const char *name,
|
||||
dir_index d_index, unsigned int mod_time,
|
||||
unsigned int 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
|
||||
{
|
||||
/* 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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
dir_index d_index;
|
||||
|
||||
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;
|
||||
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;
|
||||
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
||||
length = read_unsigned_leb128 (parent_bfd, line_ptr, &bytes_read);
|
||||
line_ptr += bytes_read;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (line_ptr > (section->buffer + section->size))
|
||||
if (line_ptr > (buf + line_data.size ()))
|
||||
complaint (_("line number info header doesn't "
|
||||
"fit in `.debug_line' section"));
|
||||
|
||||
*debug_line_ptr += unit_length + offset_size;
|
||||
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,
|
||||
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 */
|
||||
|
||||
@@ -40,4 +40,11 @@ extern void dwarf2_initialize_objfile (struct objfile *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 */
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/* 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. */
|
||||
void dump (struct objfile *objfile) override;
|
||||
|
||||
/* Calls do_expand_matching_symbols and downloads debuginfo if necessary. */
|
||||
void expand_matching_symbols
|
||||
(struct objfile *,
|
||||
const lookup_name_info &lookup_name,
|
||||
@@ -143,6 +147,14 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
|
||||
int global,
|
||||
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
|
||||
(struct objfile *objfile,
|
||||
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,
|
||||
domain_enum domain,
|
||||
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.
|
||||
It is called via "mt print objfiles".
|
||||
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
|
||||
dwarf2_gdb_index::expand_matching_symbols
|
||||
dwarf2_gdb_index::do_expand_matching_symbols
|
||||
(struct objfile *objfile,
|
||||
const lookup_name_info &name, domain_enum domain,
|
||||
int global,
|
||||
@@ -353,6 +425,29 @@ dwarf2_gdb_index::expand_matching_symbols
|
||||
}, 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
|
||||
matched, to expand corresponding CUs that were marked. IDX is the
|
||||
index of the symbol name that matched. */
|
||||
@@ -455,7 +550,7 @@ dw2_expand_marked_cus
|
||||
}
|
||||
|
||||
bool
|
||||
dwarf2_gdb_index::expand_symtabs_matching
|
||||
dwarf2_gdb_index::do_expand_symtabs_matching
|
||||
(struct objfile *objfile,
|
||||
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
||||
const lookup_name_info *lookup_name,
|
||||
@@ -504,6 +599,54 @@ dwarf2_gdb_index::expand_symtabs_matching
|
||||
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
|
||||
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
|
||||
well. */
|
||||
dwz = dwarf2_get_dwz_file (per_bfd);
|
||||
if (dwz != NULL)
|
||||
if (get_gdb_index_contents_dwz != nullptr)
|
||||
{
|
||||
mapped_gdb_index dwz_map;
|
||||
const gdb_byte *dwz_types_ignore;
|
||||
offset_type dwz_types_elements_ignore;
|
||||
dwz = dwarf2_get_dwz_file (per_bfd);
|
||||
|
||||
gdb::array_view<const gdb_byte> dwz_index_content
|
||||
= 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))
|
||||
if (dwz != nullptr)
|
||||
{
|
||||
warning (_("could not read '.gdb_index' section from %s; skipping"),
|
||||
bfd_get_filename (dwz->dwz_bfd.get ()));
|
||||
return 0;
|
||||
gdb::array_view<const gdb_byte> dwz_index_content
|
||||
= 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"),
|
||||
bfd_get_filename (dwz->dwz_bfd.get ()));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "dwarf2/attribute.h"
|
||||
#include "dwarf2/comp-unit-head.h"
|
||||
#include "dwarf2/cu.h"
|
||||
#include "dwarf2/frame.h"
|
||||
#include "dwarf2/index-cache.h"
|
||||
#include "dwarf2/index-common.h"
|
||||
#include "dwarf2/leb.h"
|
||||
@@ -80,6 +81,7 @@
|
||||
#include "gdbsupport/gdb_optional.h"
|
||||
#include "gdbsupport/underlying.h"
|
||||
#include "gdbsupport/hash_enum.h"
|
||||
#include "gdbsupport/scoped_mmap.h"
|
||||
#include "filename-seen-cache.h"
|
||||
#include "producer.h"
|
||||
#include <fcntl.h>
|
||||
@@ -95,6 +97,8 @@
|
||||
#include "split-name.h"
|
||||
#include "gdbsupport/parallel-for.h"
|
||||
#include "gdbsupport/thread-pool.h"
|
||||
#include "inferior.h"
|
||||
#include "debuginfod-support.h"
|
||||
|
||||
/* When == 1, print basic high level tracing messages.
|
||||
When > 1, be more verbose.
|
||||
@@ -2112,6 +2116,170 @@ dw2_get_file_names (dwarf2_per_cu_data *this_cu,
|
||||
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
|
||||
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 *
|
||||
dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
||||
dwarf2_base_index_functions::do_find_pc_sect_compunit_symtab
|
||||
(struct objfile *objfile,
|
||||
struct bound_minimal_symbol msymbol,
|
||||
CORE_ADDR pc,
|
||||
@@ -3199,6 +3367,32 @@ dwarf2_base_index_functions::find_pc_sect_compunit_symtab
|
||||
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
|
||||
dwarf2_base_index_functions::map_symbol_filenames
|
||||
(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);
|
||||
}
|
||||
|
||||
/* 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 ();
|
||||
|
||||
/* See dwarf2/public.h. */
|
||||
@@ -3420,10 +3637,106 @@ dwarf2_initialize_objfile (struct objfile *objfile)
|
||||
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 ();
|
||||
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. */
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "gdbsupport/hash_enum.h"
|
||||
#include "gdbsupport/function-view.h"
|
||||
#include "gdbsupport/packed.h"
|
||||
#include "dwarf2/line-header.h"
|
||||
|
||||
/* Hold 'maintenance (set|show) dwarf' commands. */
|
||||
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)
|
||||
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 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,
|
||||
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 */
|
||||
|
||||
@@ -54,7 +54,8 @@ dwarf2_section_info::get_bfd_owner () const
|
||||
section = get_containing_section ();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1242,7 +1242,7 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
|
||||
symbol_file_add_separate (debug_bfd, debugfile.c_str (),
|
||||
symfile_flags, objfile);
|
||||
}
|
||||
else
|
||||
else if (!dwarf2_has_separate_index (objfile))
|
||||
{
|
||||
has_dwarf2 = false;
|
||||
const struct bfd_build_id *build_id
|
||||
|
||||
@@ -194,6 +194,28 @@ mi_ui_out::do_redirect (ui_file *outstream)
|
||||
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
|
||||
mi_ui_out::field_separator ()
|
||||
{
|
||||
|
||||
@@ -79,6 +79,7 @@ protected:
|
||||
virtual void do_wrap_hint (int indent) override;
|
||||
virtual void do_flush () 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
|
||||
{ return true; }
|
||||
|
||||
@@ -60,6 +60,10 @@ enum objfile_flag : unsigned
|
||||
/* User requested that we do not read this objfile's symbolic
|
||||
information. */
|
||||
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);
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "gdb_bfd.h"
|
||||
#include "btrace.h"
|
||||
#include "gdbsupport/pathstuff.h"
|
||||
#include "symfile.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
@@ -613,6 +613,17 @@ public:
|
||||
/* See quick_symbol_functions. */
|
||||
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. */
|
||||
CORE_ADDR section_offset (bfd_section *section) const
|
||||
{
|
||||
@@ -699,13 +710,20 @@ public:
|
||||
|
||||
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
|
||||
partial) symbol functions for this symbol reader. */
|
||||
const std::forward_list<quick_symbol_functions_up> &
|
||||
qf_safe_range
|
||||
qf_require_partial_symbols ()
|
||||
{
|
||||
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:
|
||||
|
||||
@@ -139,19 +139,19 @@ program_space::free_all_objfiles ()
|
||||
|
||||
void
|
||||
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));
|
||||
else
|
||||
{
|
||||
auto iter = std::find_if (objfiles_list.begin (), objfiles_list.end (),
|
||||
[=] (const std::unique_ptr<::objfile> &objf)
|
||||
{
|
||||
return objf.get () == before;
|
||||
return objf.get () == after;
|
||||
});
|
||||
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 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>,
|
||||
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. */
|
||||
|
||||
class unwrapping_objfile_iterator
|
||||
template<typename UniquePtrIter>
|
||||
class unwrapping_iterator
|
||||
{
|
||||
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 &reference;
|
||||
typedef typename ::objfile **pointer;
|
||||
typedef typename objfile_list::iterator::iterator_category iterator_category;
|
||||
typedef typename objfile_list::iterator::difference_type difference_type;
|
||||
|
||||
unwrapping_objfile_iterator (objfile_list::iterator iter)
|
||||
: m_iter (std::move (iter))
|
||||
{
|
||||
}
|
||||
|
||||
objfile *operator* () const
|
||||
value_type operator* () const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool operator!= (const unwrapping_objfile_iterator &other) const
|
||||
bool operator!= (const unwrapping_reverse_objfile_iterator &other) const
|
||||
{
|
||||
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. */
|
||||
objfile_list::iterator m_iter;
|
||||
/* Start REV_BEGIN on the last objfile in OBJF_LIST. */
|
||||
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_objfile_iterator>;
|
||||
using unwrapping_objfile_range
|
||||
= iterator_range<unwrapping_iterator<objfile_list::iterator>>;
|
||||
|
||||
/* A program space represents a symbolic view of an address space.
|
||||
Roughly speaking, it holds all the data associated with a
|
||||
@@ -209,11 +294,12 @@ struct program_space
|
||||
objfiles_range objfiles ()
|
||||
{
|
||||
return objfiles_range
|
||||
(unwrapping_objfile_iterator (objfiles_list.begin ()),
|
||||
unwrapping_objfile_iterator (objfiles_list.end ()));
|
||||
(unwrapping_iterator<objfile_list::iterator> (objfiles_list.begin ()),
|
||||
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.
|
||||
The basic use is in a foreach, like:
|
||||
@@ -221,20 +307,25 @@ struct program_space
|
||||
for (objfile *objf : pspace->objfiles_safe ()) { ... }
|
||||
|
||||
This variant uses a basic_safe_iterator so that objfiles can be
|
||||
deleted during iteration. */
|
||||
objfiles_safe_range objfiles_safe ()
|
||||
deleted during iteration.
|
||||
|
||||
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
|
||||
(objfiles_range
|
||||
(unwrapping_objfile_iterator (objfiles_list.begin ()),
|
||||
unwrapping_objfile_iterator (objfiles_list.end ())));
|
||||
return objfiles_safe_reverse_range
|
||||
(objfiles_reverse_range
|
||||
(unwrapping_reverse_objfile_iterator::begin (objfiles_list),
|
||||
unwrapping_reverse_objfile_iterator::end (objfiles_list)));
|
||||
}
|
||||
|
||||
/* Add OBJFILE to the list of objfiles, putting it just before
|
||||
BEFORE. If BEFORE is nullptr, it will go at the end of the
|
||||
/* Add OBJFILE to the list of objfiles, putting it just after
|
||||
AFTER. If AFTER is nullptr, it will go at the end of the
|
||||
list. */
|
||||
void add_objfile (std::unique_ptr<objfile> &&objfile,
|
||||
struct objfile *before);
|
||||
struct objfile *after);
|
||||
|
||||
/* Remove OBJFILE from the list of objfiles. */
|
||||
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,
|
||||
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,
|
||||
enum print_what print_what, int print_args,
|
||||
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
|
||||
messages. */
|
||||
|
||||
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)
|
||||
static void
|
||||
do_print_frame_info (struct ui_out *uiout, 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)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||
int source_print;
|
||||
int location_print;
|
||||
struct ui_out *uiout = current_uiout;
|
||||
|
||||
if (!current_uiout->is_mi_like_p ()
|
||||
&& 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 == SHORT_LOCATION);
|
||||
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);
|
||||
|
||||
@@ -1185,6 +1186,23 @@ print_frame_info (const frame_print_options &fp_opts,
|
||||
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. */
|
||||
|
||||
void
|
||||
@@ -1309,13 +1327,13 @@ find_frame_funname (frame_info_ptr frame, enum language *funlang,
|
||||
}
|
||||
|
||||
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,
|
||||
enum print_what print_what, int print_args,
|
||||
struct symtab_and_line sal)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||
struct ui_out *uiout = current_uiout;
|
||||
enum language funlang = language_unknown;
|
||||
struct value_print_options opts;
|
||||
struct symbol *func;
|
||||
|
||||
@@ -109,9 +109,9 @@ objfile::has_unexpanded_symtabs ()
|
||||
objfile_debug_name (this));
|
||||
|
||||
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;
|
||||
break;
|
||||
@@ -134,9 +134,9 @@ objfile::find_last_source_symtab ()
|
||||
gdb_printf (gdb_stdlog, "qf->find_last_source_symtab (%s)\n",
|
||||
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)
|
||||
break;
|
||||
}
|
||||
@@ -167,8 +167,8 @@ objfile::forget_cached_source_info ()
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->forget_cached_source_info (this);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->forget_cached_source_info (this);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -214,17 +214,17 @@ objfile::map_symtabs_matching_filename
|
||||
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,
|
||||
match_one_filename,
|
||||
nullptr,
|
||||
nullptr,
|
||||
on_expansion,
|
||||
(SEARCH_GLOBAL_BLOCK
|
||||
| SEARCH_STATIC_BLOCK),
|
||||
UNDEF_DOMAIN,
|
||||
ALL_DOMAIN))
|
||||
if (!qf->expand_symtabs_matching (this,
|
||||
match_one_filename,
|
||||
nullptr,
|
||||
nullptr,
|
||||
on_expansion,
|
||||
(SEARCH_GLOBAL_BLOCK
|
||||
| SEARCH_STATIC_BLOCK),
|
||||
UNDEF_DOMAIN,
|
||||
ALL_DOMAIN))
|
||||
{
|
||||
retval = false;
|
||||
break;
|
||||
@@ -283,18 +283,18 @@ objfile::lookup_symbol (block_enum kind, const char *name, domain_enum domain)
|
||||
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,
|
||||
nullptr,
|
||||
&lookup_name,
|
||||
nullptr,
|
||||
search_one_symtab,
|
||||
kind == GLOBAL_BLOCK
|
||||
? SEARCH_GLOBAL_BLOCK
|
||||
: SEARCH_STATIC_BLOCK,
|
||||
domain,
|
||||
ALL_DOMAIN))
|
||||
if (!qf->expand_symtabs_matching (this,
|
||||
nullptr,
|
||||
&lookup_name,
|
||||
nullptr,
|
||||
search_one_symtab,
|
||||
kind == GLOBAL_BLOCK
|
||||
? SEARCH_GLOBAL_BLOCK
|
||||
: SEARCH_STATIC_BLOCK,
|
||||
domain,
|
||||
ALL_DOMAIN))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -314,8 +314,8 @@ objfile::print_stats (bool print_bcache)
|
||||
gdb_printf (gdb_stdlog, "qf->print_stats (%s, %d)\n",
|
||||
objfile_debug_name (this), print_bcache);
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->print_stats (this, print_bcache);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->print_stats (this, print_bcache);
|
||||
}
|
||||
|
||||
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 lookup_name = base_lookup.make_ignore_params ();
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->expand_symtabs_matching (this,
|
||||
nullptr,
|
||||
&lookup_name,
|
||||
nullptr,
|
||||
nullptr,
|
||||
(SEARCH_GLOBAL_BLOCK
|
||||
| SEARCH_STATIC_BLOCK),
|
||||
VAR_DOMAIN,
|
||||
ALL_DOMAIN);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->expand_symtabs_matching (this,
|
||||
nullptr,
|
||||
&lookup_name,
|
||||
nullptr,
|
||||
nullptr,
|
||||
(SEARCH_GLOBAL_BLOCK
|
||||
| SEARCH_STATIC_BLOCK),
|
||||
VAR_DOMAIN,
|
||||
ALL_DOMAIN);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -359,8 +359,8 @@ objfile::expand_all_symtabs ()
|
||||
gdb_printf (gdb_stdlog, "qf->expand_all_symtabs (%s)\n",
|
||||
objfile_debug_name (this));
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->expand_all_symtabs (this);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->expand_all_symtabs (this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -377,16 +377,16 @@ objfile::expand_symtabs_with_fullname (const char *fullname)
|
||||
return filename_cmp (basenames ? basename : fullname, filename) == 0;
|
||||
};
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->expand_symtabs_matching (this,
|
||||
file_matcher,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
(SEARCH_GLOBAL_BLOCK
|
||||
| SEARCH_STATIC_BLOCK),
|
||||
UNDEF_DOMAIN,
|
||||
ALL_DOMAIN);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->expand_symtabs_matching (this,
|
||||
file_matcher,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
(SEARCH_GLOBAL_BLOCK
|
||||
| SEARCH_STATIC_BLOCK),
|
||||
UNDEF_DOMAIN,
|
||||
ALL_DOMAIN);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -402,9 +402,9 @@ objfile::expand_matching_symbols
|
||||
domain_name (domain), global,
|
||||
host_address_to_string (ordered_compare));
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->expand_matching_symbols (this, name, domain, global,
|
||||
ordered_compare);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->expand_matching_symbols (this, name, domain, global,
|
||||
ordered_compare);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -429,10 +429,10 @@ objfile::expand_symtabs_matching
|
||||
host_address_to_string (&expansion_notify),
|
||||
search_domain_name (kind));
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
if (!iter->expand_symtabs_matching (this, file_matcher, lookup_name,
|
||||
symbol_matcher, expansion_notify,
|
||||
search_flags, domain, kind))
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
if (!qf->expand_symtabs_matching (this, file_matcher, lookup_name,
|
||||
symbol_matcher, expansion_notify,
|
||||
search_flags, domain, kind))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -454,10 +454,10 @@ objfile::find_pc_sect_compunit_symtab (struct bound_minimal_symbol msymbol,
|
||||
host_address_to_string (section),
|
||||
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,
|
||||
warn_if_readin);
|
||||
retval = qf->find_pc_sect_compunit_symtab (this, msymbol, pc, section,
|
||||
warn_if_readin);
|
||||
if (retval != nullptr)
|
||||
break;
|
||||
}
|
||||
@@ -482,8 +482,8 @@ objfile::map_symbol_filenames (gdb::function_view<symbol_filename_ftype> fun,
|
||||
objfile_debug_name (this),
|
||||
need_fullname);
|
||||
|
||||
for (const auto &iter : qf_require_partial_symbols ())
|
||||
iter->map_symbol_filenames (this, fun, need_fullname);
|
||||
for (quick_symbol_functions *qf : qf_require_partial_symbols ())
|
||||
qf->map_symbol_filenames (this, fun, need_fullname);
|
||||
}
|
||||
|
||||
struct compunit_symtab *
|
||||
@@ -496,9 +496,9 @@ objfile::find_compunit_symtab_by_address (CORE_ADDR address)
|
||||
hex_string (address));
|
||||
|
||||
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)
|
||||
break;
|
||||
}
|
||||
@@ -521,10 +521,10 @@ objfile::lookup_global_symbol_language (const char *name,
|
||||
enum language result = language_unknown;
|
||||
*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,
|
||||
symbol_found_p);
|
||||
result = qf->lookup_global_symbol_language (this, name, domain,
|
||||
symbol_found_p);
|
||||
if (*symbol_found_p)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -991,6 +991,10 @@ syms_from_objfile (struct objfile *objfile,
|
||||
static void
|
||||
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
|
||||
old main symbol file. Otherwise it is sufficient to fixup all the
|
||||
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);
|
||||
}
|
||||
else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0)
|
||||
else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0
|
||||
&& !was_deferred)
|
||||
{
|
||||
breakpoint_re_set ();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,23 @@ if { [gdb_compile "$sourcetmp" "${binfile}2" executable {debug build-id}] != ""
|
||||
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.
|
||||
# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
|
||||
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 lazy_support -1
|
||||
|
||||
# Setup the global variable DEBUGDIR as a directory containing the
|
||||
# debug information for the test executable.
|
||||
@@ -103,6 +121,8 @@ set corefile [standard_output_file "corefile"]
|
||||
# running.
|
||||
proc_with_prefix no_url { } {
|
||||
global binfile outputdir debugdir
|
||||
global sectexec lib_sl libfile lazy_support
|
||||
global gdb_prompt
|
||||
|
||||
setenv DEBUGINFOD_URLS ""
|
||||
|
||||
@@ -119,11 +139,18 @@ proc_with_prefix no_url { } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [gdb_gnu_strip_debug $lib_sl ""] != 0} {
|
||||
fail "strip shlib debuginfo"
|
||||
return -1
|
||||
}
|
||||
|
||||
set debugdir [standard_output_file "debug"]
|
||||
set debuginfo [standard_output_file "fetch_src_and_symbols.debug"]
|
||||
set debuginfo_shlib [standard_output_file $libfile.sl.debug]
|
||||
|
||||
file mkdir $debugdir
|
||||
file rename -force $debuginfo $debugdir
|
||||
file rename -force $debuginfo_shlib $debugdir
|
||||
|
||||
# Test that GDB cannot find symbols without debuginfod.
|
||||
clean_restart $binfile
|
||||
@@ -171,6 +198,25 @@ proc_with_prefix no_url { } {
|
||||
|
||||
clean_restart
|
||||
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
|
||||
@@ -208,6 +254,7 @@ proc disable_delete_breakpoints {} {
|
||||
# expected debug information.
|
||||
proc_with_prefix local_url { } {
|
||||
global binfile outputdir debugdir db
|
||||
global sectexec lib_sl libfile lazy_support
|
||||
|
||||
set url [start_debuginfod $db $debugdir]
|
||||
if { $url == "" } {
|
||||
@@ -256,6 +303,17 @@ proc_with_prefix local_url { } {
|
||||
"file [file tail ${binfile}_alt.o]" \
|
||||
$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.
|
||||
unsetenv DEBUGINFOD_URLS
|
||||
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}\")" \
|
||||
"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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
whether REQUESTED_THREADS is a list of global or per-inferior
|
||||
thread ids. */
|
||||
@@ -1095,82 +1195,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
|
||||
for (inferior *inf : all_inferiors ())
|
||||
for (thread_info *tp : inf->threads ())
|
||||
{
|
||||
int core;
|
||||
|
||||
any_thread = true;
|
||||
if (tp == current_thread && tp->state == THREAD_EXITED)
|
||||
current_exited = true;
|
||||
|
||||
if (!should_print_thread (requested_threads, default_inf_num,
|
||||
global_ids, pid, tp))
|
||||
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);
|
||||
print_thread (uiout, requested_threads, global_ids, pid,
|
||||
show_global_ids, default_inf_num, tp, current_thread);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
set_stream (file);
|
||||
|
||||
@@ -220,13 +220,53 @@ public:
|
||||
bool empty () const { return m_string.empty (); }
|
||||
void clear () { return m_string.clear (); }
|
||||
|
||||
private:
|
||||
protected:
|
||||
/* The internal buffer. */
|
||||
std::string m_string;
|
||||
|
||||
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 stdio_file can either own its underlying file, or not. If it
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
ui_out::redirect_to_buffer (buffer_file *buf_file)
|
||||
{
|
||||
do_redirect_to_buffer (buf_file);
|
||||
}
|
||||
|
||||
/* Test the flags against the mask given. */
|
||||
ui_out_flags
|
||||
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_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. */
|
||||
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);
|
||||
|
||||
/* 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_flush () = 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_notify (const std::string &, const char *,
|
||||
@@ -470,4 +474,66 @@ private:
|
||||
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 */
|
||||
|
||||
@@ -60,5 +60,4 @@ struct iterator_range
|
||||
private:
|
||||
IteratorType m_begin, m_end;
|
||||
};
|
||||
|
||||
#endif /* GDBSUPPORT_ITERATOR_RANGE_H */
|
||||
|
||||
Reference in New Issue
Block a user