* RFA: handle "MiniDebuginfo" section
@ 2012-11-09 17:33 Tom Tromey
2012-11-09 18:07 ` Eli Zaretskii
` (5 more replies)
0 siblings, 6 replies; 42+ messages in thread
From: Tom Tromey @ 2012-11-09 17:33 UTC (permalink / raw)
To: gdb-patches
Fedora recently approved and committed the "MiniDebuginfo" feature:
http://fedoraproject.org/wiki/Features/MiniDebugInfo
Essentially this is a way to ship some extra symbols, compressed in a
special section in an executable or library, so that backtracing can
work "well enough" without requiring full debuginfo.
This patch adds support for this feature to gdb. I think the
implementation is pretty straightforward. If you want to enable it, you
will need the LZMA library:
http://tukaani.org/lzma/
Built and regtested on x86-64 Fedora 16.
At least a doc review is required.
Tom
2012-11-09 Alexander Larsson <alexl@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* elfread.c (alloc_lzma, free_lzma): New functions.
(gdb_lzma_allocator): New global.
(struct lzma_stream): New.
(lzma_open, lzma_pread, lzma_close, lzma_stat)
(find_separate_debug_file_in_section): New functions.
(elf_symfile_read): Call find_separate_debug_file_in_section if no
other debuginfo is found.
* configure.ac: Check for lzma.
* configure, config.in: Rebuild.
* Makefile.in (LIBLZMA): New variable.
(CLIBS): Include LIBLZMA.
* NEWS: Mention mini debuginfo feature.
2012-11-09 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Separate Debug Section): New node.
(GDB Files): Update.
2012-11-09 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.dwarf2/dw2-gnu-debugdata.exp: New file.
* gdb.dwarf2/dw2-gnu-debugdata.c: New file.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9e7702d..a78917e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@
# Where is expat? This will be empty if expat was not available.
LIBEXPAT = @LIBEXPAT@
+# Where is lzma? This will be empty if lzma was not available.
+LIBLZMA = @LIBLZMA@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) \
+ $(LIBEXPAT) $(LIBLZMA) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/NEWS b/gdb/NEWS
index 8567742..2102d90 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -67,6 +67,11 @@ py [command]
** Memory changes are now notified using new async record
"=memory-changed".
+* GDB now supports the "mini debuginfo" section, .gnu_debugdata.
+ You must have the LZMA library available when configuring GDB for this
+ feature to be enabled. For more information, see:
+ http://fedoraproject.org/wiki/Features/MiniDebugInfo
+
*** Changes in GDB 7.5
* GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/>
diff --git a/gdb/configure.ac b/gdb/configure.ac
index f0b7df3..c751c2d 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2056,6 +2056,27 @@ LIBS=$OLD_LIBS
# Add any host-specific objects to GDB.
CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}"
+# If building on ELF, look for lzma support for embedded compressed debug info.
+if test $gdb_cv_var_elf = yes; then
+ AC_ARG_WITH(lzma,
+ AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]),
+ [], [with_lzma=auto])
+ AC_MSG_CHECKING([whether to use lzma])
+ AC_MSG_RESULT([$with_lzma])
+
+ if test "${with_lzma}" != no; then
+ AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"],
+ [lzma_index_iter iter;
+ lzma_index_iter_init (&iter, 0);
+ lzma_mf_is_supported (LZMA_MF_HC3);])
+ if test "$HAVE_LIBLZMA" != yes; then
+ if test "$with_lzma" = yes; then
+ AC_MSG_ERROR([missing liblzma for --with-lzma])
+ fi
+ fi
+ fi
+fi
+
LIBGUI="../libgui/src/libgui.a"
GUI_CFLAGS_X="-I${srcdir}/../libgui/src"
AC_SUBST(LIBGUI)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 50fc123..8c85a19 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -15787,6 +15787,7 @@ program. To debug a core dump of a previous run, you must also tell
@menu
* Files:: Commands to specify files
* Separate Debug Files:: Debugging information in separate files
+* Separate Debug Section:: Debugging information in a special section
* Index Files:: Index files speed up GDB
* Symbol Errors:: Errors reading symbol files
* Data Files:: GDB data files
@@ -16712,6 +16713,44 @@ gnu_debuglink_crc32 (unsigned long crc,
@noindent
This computation does not apply to the ``build ID'' method.
+@node Separate Debug Section
+@section Debugging information in a special section
+@cindex separate debug sections
+@cindex @samp{.gnu_debugdata} section
+
+Some systems ship pre-built executables and libraries that have a
+special @samp{.gnu_debugdata} section. This section holds an
+LZMA-compressed ELF object and is used to supply extra symbols for
+backtraces. @value{GDBN} has support for this extension.
+
+This section can be easily created using @command{objcopy} and other
+standard utilities:
+
+@smallexample
+# Extract the dynamic symbols from the main binary, there is no need
+# to also have these in the normal symbol table
+nm -D @var{binary} --format=posix --defined-only \
+ | awk '@{ print $1 @}' | sort > dynsyms
+
+# Extract all the text (i.e. function) symbols from the debuginfo .
+nm @var{binary} --format=posix --defined-only \
+ | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \
+ | sort > funcsyms
+
+# Keep all the function symbols not already in the dynamic symbol
+# table.
+comm -13 dynsyms funcsyms > keep_symbols
+
+# Copy the full debuginfo, keeping only a minimal set of symbols and
+# removing some unnecessary sections.
+objcopy -S --remove-section .gdb_index --remove-section .comment \
+ --keep-symbols=keep_symbols @var{binary} mini_debuginfo
+
+# Inject the compressed data into the .gnu_debugdata section of the
+# original binary.
+xz mini_debuginfo
+objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary}
+@end smallexample
@node Index Files
@section Index Files Speed Up @value{GDBN}
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 516cbd0..789b649 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -45,6 +45,10 @@
#include "regcache.h"
#include "bcache.h"
#include "gdb_bfd.h"
+#include "gdbcore.h"
+#ifdef HAVE_LIBLZMA
+# include <lzma.h>
+#endif
extern void _initialize_elfread (void);
@@ -1214,6 +1218,264 @@ find_separate_debug_file_by_buildid (struct objfile *objfile)
return NULL;
}
+#ifdef HAVE_LIBLZMA
+
+/* Custom lzma_allocator.alloc so they use the gdb ones. */
+
+static void *
+alloc_lzma (void *opaque, size_t nmemb, size_t size)
+{
+ return xmalloc (nmemb * size);
+}
+
+/* Custom lzma_allocator.free so they use the gdb ones. */
+
+static void
+free_lzma (void *opaque, void *ptr)
+{
+ xfree (ptr);
+}
+
+/* It cannot be const due to the lzma library function prototypes. */
+
+static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL};
+
+/* Custom bfd_openr_iovec implementation to read compressed data from a
+ section. This keeps only the last decompressed block in memory to
+ allow larger data without using to much memory. */
+
+struct lzma_stream
+{
+ /* Section of input BFD we are decoding data from. */
+ asection *section;
+
+ /* lzma library decompression state. */
+ lzma_index *index;
+
+ /* Currently decoded block. */
+ bfd_size_type data_start;
+ bfd_size_type data_end;
+ gdb_byte *data;
+};
+
+/* bfd_openr_iovec OPEN_P implementation for
+ find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' of the
+ section to decompress.
+
+ Return 'struct lzma_stream *' must be freed by caller by xfree, together
+ with its INDEX lzma data. */
+
+static void *
+lzma_open (struct bfd *nbfd, void *open_closure)
+{
+ asection *section = open_closure;
+ bfd_size_type size, offset;
+ lzma_stream_flags options;
+ gdb_byte footer[LZMA_STREAM_HEADER_SIZE];
+ gdb_byte *indexdata;
+ lzma_index *index;
+ int ret;
+ uint64_t memlimit = UINT64_MAX;
+ struct lzma_stream *lstream;
+ size_t pos;
+
+ size = bfd_get_section_size (section);
+ offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE;
+ if (size < LZMA_STREAM_HEADER_SIZE
+ || bfd_seek (section->owner, offset, SEEK_SET) != 0
+ || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner)
+ != LZMA_STREAM_HEADER_SIZE
+ || lzma_stream_footer_decode (&options, footer) != LZMA_OK
+ || offset < options.backward_size)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ offset -= options.backward_size;
+ indexdata = xmalloc (options.backward_size);
+ index = NULL;
+ pos = 0;
+ if (bfd_seek (section->owner, offset, SEEK_SET) != 0
+ || bfd_bread (indexdata, options.backward_size, section->owner)
+ != options.backward_size
+ || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator,
+ indexdata, &pos, options.backward_size)
+ != LZMA_OK
+ || lzma_index_size (index) != options.backward_size)
+ {
+ xfree (indexdata);
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+ xfree (indexdata);
+
+ lstream = xzalloc (sizeof (struct lzma_stream));
+ lstream->section = section;
+ lstream->index = index;
+
+ return lstream;
+}
+
+/* bfd_openr_iovec PREAD_P implementation for
+ find_separate_debug_file_in_section. Passed STREAM
+ is 'struct lzma_stream *'. */
+
+static file_ptr
+lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes,
+ file_ptr offset)
+{
+ struct lzma_stream *lstream = stream;
+ bfd_size_type chunk_size;
+ lzma_index_iter iter;
+ gdb_byte *compressed, *uncompressed;
+ file_ptr block_offset;
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ lzma_block block;
+ size_t compressed_pos, uncompressed_pos;
+ file_ptr res;
+
+ res = 0;
+ while (nbytes > 0)
+ {
+ if (lstream->data == NULL
+ || lstream->data_start > offset || offset >= lstream->data_end)
+ {
+ asection *section = lstream->section;
+
+ lzma_index_iter_init (&iter, lstream->index);
+ if (lzma_index_iter_locate (&iter, offset))
+ break;
+
+ compressed = xmalloc (iter.block.total_size);
+ block_offset = section->filepos + iter.block.compressed_file_offset;
+ if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0
+ || bfd_bread (compressed, iter.block.total_size, section->owner)
+ != iter.block.total_size)
+ {
+ xfree (compressed);
+ break;
+ }
+
+ uncompressed = xmalloc (iter.block.uncompressed_size);
+
+ memset (&block, 0, sizeof (block));
+ block.filters = filters;
+ block.header_size = lzma_block_header_size_decode (compressed[0]);
+ if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed)
+ != LZMA_OK)
+ {
+ xfree (compressed);
+ xfree (uncompressed);
+ break;
+ }
+
+ compressed_pos = block.header_size;
+ uncompressed_pos = 0;
+ if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator,
+ compressed, &compressed_pos,
+ iter.block.total_size,
+ uncompressed, &uncompressed_pos,
+ iter.block.uncompressed_size)
+ != LZMA_OK)
+ {
+ xfree (compressed);
+ xfree (uncompressed);
+ break;
+ }
+
+ xfree (compressed);
+
+ xfree (lstream->data);
+ lstream->data = uncompressed;
+ lstream->data_start = iter.block.uncompressed_file_offset;
+ lstream->data_end = (iter.block.uncompressed_file_offset
+ + iter.block.uncompressed_size);
+ }
+
+ chunk_size = min (nbytes, lstream->data_end - offset);
+ memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size);
+ buf = (gdb_byte *) buf + chunk_size;
+ offset += chunk_size;
+ nbytes -= chunk_size;
+ res += chunk_size;
+ }
+
+ return res;
+}
+
+/* bfd_openr_iovec CLOSE_P implementation for
+ find_separate_debug_file_in_section. Passed STREAM
+ is 'struct lzma_stream *'. */
+
+static int
+lzma_close (struct bfd *nbfd,
+ void *stream)
+{
+ struct lzma_stream *lstream = stream;
+
+ lzma_index_end (lstream->index, &gdb_lzma_allocator);
+ xfree (lstream->data);
+ xfree (lstream);
+ return 0;
+}
+
+/* bfd_openr_iovec STAT_P implementation for
+ find_separate_debug_file_in_section. Passed STREAM
+ is 'struct lzma_stream *'. */
+
+static int
+lzma_stat (struct bfd *abfd,
+ void *stream,
+ struct stat *sb)
+{
+ struct lzma_stream *lstream = stream;
+
+ sb->st_size = lzma_index_uncompressed_size (lstream->index);
+ return 0;
+}
+
+/* This looks for a xz compressed separate debug info object file embedded
+ in a section called .gnu_debugdata. See
+ http://fedoraproject.org/wiki/Features/MiniDebugInfo
+ or the "Separate Debug Sections" of the manual for details.
+ If we find one we create a iovec based bfd that decompresses the
+ object data on demand. If we don't find one, return NULL. */
+
+static bfd *
+find_separate_debug_file_in_section (struct objfile *objfile)
+{
+ asection *section;
+ bfd *abfd;
+
+ section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata");
+ if (section == NULL)
+ return NULL;
+
+ abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section,
+ lzma_pread, lzma_close, lzma_stat);
+ if (abfd == NULL)
+ return NULL;
+
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ gdb_bfd_unref (abfd);
+ return NULL;
+ }
+
+ return abfd;
+}
+
+#else /* !HAVE_LIBLZMA */
+
+static bfd *
+find_separate_debug_file_in_section (struct objfile *objfile)
+{
+ return NULL;
+}
+
+#endif /* !HAVE_LIBLZMA */
+
/* Scan and build partial symbols for a symbol file.
We have been initialized by a call to elf_symfile_init, which
currently does nothing.
@@ -1437,21 +1699,31 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags)
else if (!objfile_has_partial_symbols (objfile))
{
char *debugfile;
+ bfd *abfd = NULL;
+ struct cleanup *cleanup;
debugfile = find_separate_debug_file_by_buildid (objfile);
if (debugfile == NULL)
debugfile = find_separate_debug_file_by_debuglink (objfile);
+ cleanup = make_cleanup (xfree, debugfile);
if (debugfile)
{
- struct cleanup *cleanup = make_cleanup (xfree, debugfile);
- bfd *abfd = symfile_bfd_open (debugfile);
+ abfd = symfile_bfd_open (debugfile);
+ make_cleanup_bfd_unref (abfd);
+ }
+ if (abfd == NULL)
+ {
+ abfd = find_separate_debug_file_in_section (objfile);
make_cleanup_bfd_unref (abfd);
- symbol_file_add_separate (abfd, symfile_flags, objfile);
- do_cleanups (cleanup);
}
+
+ if (abfd != NULL)
+ symbol_file_add_separate (abfd, symfile_flags, objfile);
+
+ do_cleanups (cleanup);
}
if (symtab_create_debug)
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.c b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.c
new file mode 100644
index 0000000..b8b7e8a
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.c
@@ -0,0 +1,30 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 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 <signal.h>
+
+static int
+debugdata_function (void)
+{
+ return raise (SIGSEGV) + 1;
+}
+
+int
+main (void)
+{
+ return debugdata_function () + 1;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp
new file mode 100644
index 0000000..e384412
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp
@@ -0,0 +1,98 @@
+# Copyright 2012 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/>.
+
+standard_testfile
+
+load_lib dwarf.exp
+if ![dwarf2_support] {
+ return 0
+}
+
+if [build_executable ${testfile}.exp $testfile] {
+ return -1
+}
+
+proc run { test cmdline } {
+ verbose "cmdline is $cmdline"
+ set result [catch "exec $cmdline" output]
+ verbose "result is $result"
+ verbose "output is $output"
+ if {$result == 0} {
+ pass $test
+ return 0
+ } else {
+ fail $test
+ return -1
+ }
+}
+
+set strip_program [transform strip]
+set nm_program [transform nm]
+
+# Extract the dynamic symbols from the main binary, there is no need
+# to also have these in the normal symbol table.
+file delete -- ${binfile}.dynsyms
+if [run "nm -D" "[transform nm] -D ${binfile} --format=posix --defined-only | awk \\{print\\ \\\$1\\} | sort > ${binfile}.dynsyms"] {
+ return -1
+}
+
+# Extract all the text (i.e. function) symbols from the debuginfo.
+file delete -- ${binfile}.funcsyms
+if [run "nm" "[transform nm] ${binfile} --format=posix --defined-only | awk \\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\} | sort > ${binfile}.funcsyms"] {
+ return -1
+}
+
+# Keep all the function symbols not already in the dynamic symbol
+# table.
+file delete -- ${binfile}.keep_symbols
+if [run "comm" "comm -13 ${binfile}.dynsyms ${binfile}.funcsyms > ${binfile}.keep_symbols"] {
+ return -1
+}
+
+# Copy the full debuginfo, keeping only a minimal set of symbols and
+# removing some unnecessary sections.
+file delete -- ${binfile}.mini_debuginfo
+if [run "objcopy 1" "[transform objcopy] -S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"] {
+ return -1
+}
+
+# GDB specific - we do not have split executable in advance.
+file delete -- ${binfile}.strip
+if [run "strip" "[transform strip] --strip-all -o ${binfile}.strip ${binfile}"] {
+ return -1
+}
+
+# Inject the compressed data into the .gnu_debugdata section of the
+# original binary.
+file delete -- ${binfile}.mini_debuginfo.xz
+if [run "xz" "xz ${binfile}.mini_debuginfo"] {
+ return -1
+}
+file delete -- ${binfile}.test
+if [run "objcopy 2" "[transform objcopy] --add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"] {
+ return -1
+}
+
+clean_restart "$testfile.strip"
+
+gdb_test "p debugdata_function" \
+ {No symbol table is loaded\. Use the "file" command\.} \
+ "no symtab"
+
+clean_restart "$testfile.test"
+
+gdb_test "p debugdata_function" \
+ { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \
+ "have symtab"
^ permalink raw reply [flat|nested] 42+ messages in thread* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey @ 2012-11-09 18:07 ` Eli Zaretskii 2012-11-09 18:13 ` Pedro Alves ` (4 subsequent siblings) 5 siblings, 0 replies; 42+ messages in thread From: Eli Zaretskii @ 2012-11-09 18:07 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > From: Tom Tromey <tromey@redhat.com> > Date: Fri, 09 Nov 2012 10:33:27 -0700 > > Fedora recently approved and committed the "MiniDebuginfo" feature: > > http://fedoraproject.org/wiki/Features/MiniDebugInfo > > Essentially this is a way to ship some extra symbols, compressed in a > special section in an executable or library, so that backtracing can > work "well enough" without requiring full debuginfo. > > This patch adds support for this feature to gdb. I think the > implementation is pretty straightforward. If you want to enable it, you > will need the LZMA library: > > http://tukaani.org/lzma/ > > Built and regtested on x86-64 Fedora 16. > > At least a doc review is required. The doc parts are OK. Thanks. ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey 2012-11-09 18:07 ` Eli Zaretskii @ 2012-11-09 18:13 ` Pedro Alves 2012-11-09 21:28 ` Tom Tromey 2012-11-09 18:23 ` Joel Brobecker ` (3 subsequent siblings) 5 siblings, 1 reply; 42+ messages in thread From: Pedro Alves @ 2012-11-09 18:13 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches There doesn't seem to be anything elf specific here. It seems to me this should work fine with any other container, such as coff/pe in coff/pe, for example. Can we move most of this code out of elf.c, or at least the gross of it, even if elf_symfile_read remains unchanged? I'd suggest putting it in a new file. > +#ifdef HAVE_LIBLZMA > + > +/* Custom lzma_allocator.alloc so they use the gdb ones. */ > + > +static void * > +alloc_lzma (void *opaque, size_t nmemb, size_t size) > +{ > + return xmalloc (nmemb * size); > +} > + > +/* Custom lzma_allocator.free so they use the gdb ones. */ > + > +static void > +free_lzma (void *opaque, void *ptr) > +{ > + xfree (ptr); > +} > + > +/* It cannot be const due to the lzma library function prototypes. */ > + > +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL}; Missing space after NULL. (I find the "It" or "they" in these sentences confusing, but I don't know whether that's just me and language barrier.) > +/* Custom bfd_openr_iovec implementation to read compressed data from a > + section. This keeps only the last decompressed block in memory to Missing space after '.'. > diff --git a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp > new file mode 100644 > index 0000000..e384412 > --- /dev/null > +++ b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp Seems like this won't work with remote hosts as is. Can we make it use "remote_file host delete", "remote_spawn host", etc.? If not, perhaps just bail early if [is_remote host]. -- Pedro Alves ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 18:13 ` Pedro Alves @ 2012-11-09 21:28 ` Tom Tromey 2012-11-13 12:56 ` Pedro Alves 0 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-09 21:28 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro> Seems like this won't work with remote hosts as is. Can we make Pedro> it use "remote_file host delete", "remote_spawn host", etc.? If Pedro> not, perhaps just bail early if [is_remote host]. FWIW, I took a stab at this, using the appended patch. However, I could not get it to work. I always get an error: ERROR: bad spawn_id (process died earlier?) while executing "expect { -i $spawn_id -timeout $timeout -re ".+" { append output $expect_out(buffer) if { [string length $output] < 512000 } { exp_contin..." (procedure "local_exec" line 94) invoked from within [...] I don't know if this is my bug, or dejagnu's, or expect's -- but I couldn't find a way to work around it. According to comments in remote.exp it is not ok to use redirections in a remote_exec. So I am going to just skip the remote host case. Tom diff --git a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp index e384412..85391e6 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp @@ -24,12 +24,20 @@ if [build_executable ${testfile}.exp $testfile] { return -1 } -proc run { test cmdline } { - verbose "cmdline is $cmdline" - set result [catch "exec $cmdline" output] +source /tmp/remote.exp + +set pipeline_counter 0 + +# A wrapper for 'remote_exec host' that passes or fails a test. +# Returns 0 if all went well, nonzero on failure. +# TEST is the name of the test, other arguments are as for +# remote_exec. +proc run {test program args} { + verbose -log "cmdline is remote_exec host $program $args" + set result [eval remote_exec host [list $program] $args] verbose "result is $result" - verbose "output is $output" - if {$result == 0} { + lassign $result output status + if {$status == 0} { pass $test return 0 } else { @@ -38,50 +46,89 @@ proc run { test cmdline } { } } -set strip_program [transform strip] -set nm_program [transform nm] +# Run a pipeline of processes through 'run'. +# TEST is the base name of the test, it is modified and passed to 'run'. +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. +# It is passed to 'run'. However, before being passed, if input and output +# files are not specified in the list, then this proc provides them. +# Each program in the pipeline takes its input from the previous +# program's output. +proc pipeline {test args} { + global pipeline_counter + + set input_file {} + foreach arglist $args { + verbose -log "raw args are $arglist" + lassign $arglist program arguments input output + + if {$input == ""} { + set input $input_file + } + if {$output == ""} { + set output pipe.[pid].$pipeline_counter + incr pipeline_counter + } + verbose -log "cooked args are [list $program $arguments $input $output]" + + if {[run "$test - invoke $program" $program $arguments \ + $input $output]} { + return -1 + } + + set input_file $output + } + return 0 +} # Extract the dynamic symbols from the main binary, there is no need # to also have these in the normal symbol table. -file delete -- ${binfile}.dynsyms -if [run "nm -D" "[transform nm] -D ${binfile} --format=posix --defined-only | awk \\{print\\ \\\$1\\} | sort > ${binfile}.dynsyms"] { +remote_file host delete ${binfile}.dynsyms +if {[pipeline "nm -D" \ + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ + [list awk "\\{print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.dynsyms"]]} { return -1 } # Extract all the text (i.e. function) symbols from the debuginfo. -file delete -- ${binfile}.funcsyms -if [run "nm" "[transform nm] ${binfile} --format=posix --defined-only | awk \\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\} | sort > ${binfile}.funcsyms"] { +remote_file host delete ${binfile}.funcsyms +if {[pipeline "nm" \ + [list [transform nm] "${binfile} --format=posix --defined-only"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.funcsyms"]]} { return -1 } # Keep all the function symbols not already in the dynamic symbol # table. -file delete -- ${binfile}.keep_symbols -if [run "comm" "comm -13 ${binfile}.dynsyms ${binfile}.funcsyms > ${binfile}.keep_symbols"] { +remote_file host delete ${binfile}.keep_symbols +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ + "${binfile}.keep_symbols"]} { return -1 } # Copy the full debuginfo, keeping only a minimal set of symbols and # removing some unnecessary sections. -file delete -- ${binfile}.mini_debuginfo -if [run "objcopy 1" "[transform objcopy] -S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"] { +remote_file host delete ${binfile}.mini_debuginfo +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { return -1 } # GDB specific - we do not have split executable in advance. -file delete -- ${binfile}.strip -if [run "strip" "[transform strip] --strip-all -o ${binfile}.strip ${binfile}"] { +remote_file host delete ${binfile}.strip +if {[run "strip" [transform strip] \ + "--strip-all -o ${binfile}.strip ${binfile}"]} { return -1 } # Inject the compressed data into the .gnu_debugdata section of the # original binary. -file delete -- ${binfile}.mini_debuginfo.xz -if [run "xz" "xz ${binfile}.mini_debuginfo"] { +remote_file host delete ${binfile}.mini_debuginfo.xz +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { return -1 } -file delete -- ${binfile}.test -if [run "objcopy 2" "[transform objcopy] --add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"] { +remote_file host delete ${binfile}.test +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { return -1 } ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 21:28 ` Tom Tromey @ 2012-11-13 12:56 ` Pedro Alves 2012-11-13 15:26 ` Pedro Alves 2012-11-13 18:32 ` Tom Tromey 0 siblings, 2 replies; 42+ messages in thread From: Pedro Alves @ 2012-11-13 12:56 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 11/09/2012 09:27 PM, Tom Tromey wrote: > Pedro> Seems like this won't work with remote hosts as is. Can we make > Pedro> it use "remote_file host delete", "remote_spawn host", etc.? If > Pedro> not, perhaps just bail early if [is_remote host]. > > FWIW, I took a stab at this, using the appended patch. > However, I could not get it to work. I always get an error: > > ERROR: bad spawn_id (process died earlier?) > while executing > "expect { > -i $spawn_id -timeout $timeout -re ".+" { > append output $expect_out(buffer) > if { [string length $output] < 512000 } { > exp_contin..." > (procedure "local_exec" line 94) > invoked from within > [...] > > > I don't know if this is my bug, or dejagnu's, or expect's -- but I > couldn't find a way to work around it. I did some experimenting, and found that the problem is in args passed to remote_exec. Specifically, leaving input empty, while specifying an output at the same time. Using "/dev/null" instead works. See patch below. I wondered if /dev/null would work on Windows, so I did a google search for remote_exec and /dev/null, and found that returns hits in the binutils testsuite, ... testsuite/lib/ld-lib.exp:70: remote_exec host "$ld --version" "" "/dev/null" "ld.version" testsuite/lib/ld-lib.exp:91: set status [remote_exec host [concat sh -c [list "$prog $command 2>&1"]] "" "/dev/null" "ld.tmp"] testsuite/lib/ld-lib.exp:299: set status [remote_exec host [concat sh -c [list "$cc $flags $ccflags -c $source -o $object 2>&1"]] "" "/dev/null" "ld.tmp"] ... so that does sound like the way to go. In sum, OK: remote_exec host program "" "/dev/null" "output" Not OK: remote_exec host program "" "" "output" I see one FAIL though. Exactly the same with your original patch that didn't do any remote_exec stuff, and with the fixed remote_exec stuff: (gdb) kill The program is not being run. (gdb) file /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.test Reading symbols from /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.test...(no debugging symbols found)...done. (gdb) p debugdata_function No symbol table is loaded. Use the "file" command. (gdb) FAIL: gdb.dwarf2/dw2-gnu-debugdata.exp: have symtab testcase ../../../src/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp completed in 1 seconds I haven't tried your new updated patch yet. gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp index 85391e6..8aaf97f 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp @@ -24,19 +24,24 @@ if [build_executable ${testfile}.exp $testfile] { return -1 } -source /tmp/remote.exp - -set pipeline_counter 0 - # A wrapper for 'remote_exec host' that passes or fails a test. # Returns 0 if all went well, nonzero on failure. # TEST is the name of the test, other arguments are as for # remote_exec. proc run {test program args} { verbose -log "cmdline is remote_exec host $program $args" - set result [eval remote_exec host [list $program] $args] + + # "" -> "/dev/null" + if { [llength $args] > 1 } { + if {[lindex $args 1] == ""} { + set args [lreplace $args 1 1 "/dev/null"] + } + } + + set result [eval remote_exec host $program $args] + verbose "result is $result" - lassign $result output status + lassign $result status output if {$status == 0} { pass $test return 0 @@ -54,7 +59,7 @@ proc run {test program args} { # Each program in the pipeline takes its input from the previous # program's output. proc pipeline {test args} { - global pipeline_counter + set pipeline_counter 0 set input_file {} foreach arglist $args { @@ -68,7 +73,7 @@ proc pipeline {test args} { set output pipe.[pid].$pipeline_counter incr pipeline_counter } - verbose -log "cooked args are [list $program $arguments $input $output]" + verbose -log "cooked args are: $program [list $arguments $input $output]" if {[run "$test - invoke $program" $program $arguments \ $input $output]} { ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 12:56 ` Pedro Alves @ 2012-11-13 15:26 ` Pedro Alves 2012-11-13 18:32 ` Tom Tromey 1 sibling, 0 replies; 42+ messages in thread From: Pedro Alves @ 2012-11-13 15:26 UTC (permalink / raw) To: gdb-patches; +Cc: Tom Tromey On 11/13/2012 12:56 PM, Pedro Alves wrote: > I see one FAIL though. Exactly the same with your original patch that > didn't do any remote_exec stuff, and with the fixed remote_exec stuff: > > (gdb) kill > The program is not being run. > (gdb) file /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.test > Reading symbols from /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.test...(no debugging symbols found)...done. > (gdb) p debugdata_function > No symbol table is loaded. Use the "file" command. > (gdb) FAIL: gdb.dwarf2/dw2-gnu-debugdata.exp: have symtab > testcase ../../../src/gdb/testsuite/gdb.dwarf2/dw2-gnu-debugdata.exp completed in 1 seconds For the archives, the issue was that I didn't have lzma support in my GDB build: (gdb) file /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.base/gnu-debugdata.test Reading symbols from /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.base/gnu-debugdata.test...warning: Cannot parse .gnu_debugdata section; LZMA support was disabled at compile time (no debugging symbols found)...done. (gdb) p debugdata_function No symbol table is loaded. Use the "file" command. (gdb) FAIL: gdb.base/gnu-debugdata.exp: have symtab Tom already said he'll make the test check that. ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 12:56 ` Pedro Alves 2012-11-13 15:26 ` Pedro Alves @ 2012-11-13 18:32 ` Tom Tromey 1 sibling, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-13 18:32 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches >>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: Pedro> I did some experimenting, and found that the problem is in args Pedro> passed to remote_exec. Specifically, leaving input empty, while Pedro> specifying an output at the same time. Using "/dev/null" instead Pedro> works. See patch below. I wondered if /dev/null would work on Pedro> Windows, so I did a google search for remote_exec and /dev/null, Pedro> and found that returns hits in the binutils testsuite, Thanks for doing this. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey 2012-11-09 18:07 ` Eli Zaretskii 2012-11-09 18:13 ` Pedro Alves @ 2012-11-09 18:23 ` Joel Brobecker 2012-11-09 18:53 ` Pedro Alves ` (2 more replies) 2012-11-12 16:28 ` Tom Tromey ` (2 subsequent siblings) 5 siblings, 3 replies; 42+ messages in thread From: Joel Brobecker @ 2012-11-09 18:23 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > Fedora recently approved and committed the "MiniDebuginfo" feature: > > http://fedoraproject.org/wiki/Features/MiniDebugInfo Looks pretty nice :) > This patch adds support for this feature to gdb. I think the > implementation is pretty straightforward. If you want to enable it, you > will need the LZMA library: > > http://tukaani.org/lzma/ I went to the website to see which formats it supports, and was surprised to read: Users of LZMA Utils should move to XZ Utils. X Shouldn't we just switch to xzutils instead? > 2012-11-09 Alexander Larsson <alexl@redhat.com> > Jan Kratochvil <jan.kratochvil@redhat.com> > > * elfread.c (alloc_lzma, free_lzma): New functions. > (gdb_lzma_allocator): New global. > (struct lzma_stream): New. > (lzma_open, lzma_pread, lzma_close, lzma_stat) > (find_separate_debug_file_in_section): New functions. > (elf_symfile_read): Call find_separate_debug_file_in_section if no > other debuginfo is found. Should we put the lzma-support code into its own file? I think it would be cleaner, and also shows that this isn't really tied to ELF. Perhaps there will be compressed sections in other file formats, someday? To avoid the #ifdef HAVE_LZMA, I might even provide two versions of the file, one with the real implementation, and one with the phony one, and have the configure choose which one to link in. This isn't what we've been doing in the past (iconv, python), so to be taken with a grain of salt. I think it'll make the code a little easier to navigate, however. > * configure.ac: Check for lzma. > * configure, config.in: Rebuild. > * Makefile.in (LIBLZMA): New variable. > (CLIBS): Include LIBLZMA. > * NEWS: Mention mini debuginfo feature. Otherwise, nicely clean and documented code! -- Joel ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 18:23 ` Joel Brobecker @ 2012-11-09 18:53 ` Pedro Alves 2012-11-09 19:13 ` Tom Tromey 2012-11-12 16:04 ` Tom Tromey 2 siblings, 0 replies; 42+ messages in thread From: Pedro Alves @ 2012-11-09 18:53 UTC (permalink / raw) To: Joel Brobecker; +Cc: Tom Tromey, gdb-patches On 11/09/2012 06:23 PM, Joel Brobecker wrote: > To avoid the #ifdef HAVE_LZMA, I might even provide two versions of the > file, one with the real implementation, and one with the phony one, and > have the configure choose which one to link in. This isn't what we've > been doing in the past (iconv, python), so to be taken with a grain of > salt. I think it'll make the code a little easier to navigate, however. See xml-tdesc.c, where we do something similar, but not in separate files (which I actually prefer, for being simpler). In that case, we warn once if xml support isn't built in. It could be useful here too, not sure: warning: Can not parse .gnu_debugdata section; LZMA support was disabled at compile time -- Pedro Alves ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 18:23 ` Joel Brobecker 2012-11-09 18:53 ` Pedro Alves @ 2012-11-09 19:13 ` Tom Tromey 2012-11-12 16:04 ` Tom Tromey 2 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-09 19:13 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches >>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes: Joel> To avoid the #ifdef HAVE_LZMA, I might even provide two versions of the Joel> file, one with the real implementation, and one with the phony one, and Joel> have the configure choose which one to link in. This isn't what we've Joel> been doing in the past (iconv, python), so to be taken with a grain of Joel> salt. I think it'll make the code a little easier to navigate, however. To me this seems like a lot of work for a single function. And, it doesn't make the code less complicated -- the "#if" is still there, just in configure and Makefile.in rather than in the C. I tend to find the C code more readable than those, which is something I like about the current approach. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 18:23 ` Joel Brobecker 2012-11-09 18:53 ` Pedro Alves 2012-11-09 19:13 ` Tom Tromey @ 2012-11-12 16:04 ` Tom Tromey 2012-11-12 17:04 ` Joel Brobecker 2 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-12 16:04 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches >>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes: Tom> http://tukaani.org/lzma/ Joel> I went to the website to see which formats it supports, and was Joel> surprised to read: Joel> Users of LZMA Utils should move to XZ Utils. Joel> Shouldn't we just switch to xzutils instead? I think it is just the same thing with a different name. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-12 16:04 ` Tom Tromey @ 2012-11-12 17:04 ` Joel Brobecker 2012-11-12 18:24 ` Tom Tromey 0 siblings, 1 reply; 42+ messages in thread From: Joel Brobecker @ 2012-11-12 17:04 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > Joel> I went to the website to see which formats it supports, and was > Joel> surprised to read: > Joel> Users of LZMA Utils should move to XZ Utils. > Joel> Shouldn't we just switch to xzutils instead? > > I think it is just the same thing with a different name. In that case, why not switch right away to xz-utils, then? Wouldn't be the case of s/lzma/xz/ with a few fixups here and there? We know we're going to have to do eventually, since lzma-utils has been obsoleted in favor of xz-utils. And if it's just a naming issue, it should be relatively easy to do? I'm just trying to save some work in the long run, but if you prefer staying with lzma-utils, then it's fine with me... -- Joel ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-12 17:04 ` Joel Brobecker @ 2012-11-12 18:24 ` Tom Tromey 0 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-12 18:24 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches >>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes: Joel> In that case, why not switch right away to xz-utils, then? Wouldn't Joel> be the case of s/lzma/xz/ with a few fixups here and there? I looked and I actually had sent out the wrong URL. My build picks up xz-devel for these libraries, and that comes from http://tukaani.org/xz/ So, I think there is nothing to do here. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey ` (2 preceding siblings ...) 2012-11-09 18:23 ` Joel Brobecker @ 2012-11-12 16:28 ` Tom Tromey 2012-11-13 18:36 ` Tom Tromey 2012-11-12 21:26 ` Doug Evans 2012-11-13 15:44 ` Jan Kratochvil 5 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-12 16:28 UTC (permalink / raw) To: gdb-patches >>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes: Tom> Fedora recently approved and committed the "MiniDebuginfo" feature: Tom> http://fedoraproject.org/wiki/Features/MiniDebugInfo Here is a new version of the patch. I think I've addressed all the review comments. The new LZMA-using code is now in a new file. I made the new code not be ELF-specific; instead it is a general fallback implemented in symfile.c. I added a warning in the case where the new section is available and would be used, but can't be since LZMA wasn't compiled in. I renamed the test file since I think it isn't DWARF-specific. Tom 2012-11-12 Alexander Larsson <alexl@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention mini debuginfo feature. * minidebug.c: New file. * configure.ac: Check for lzma. * configure, config.in: Rebuild. * Makefile.in (LIBLZMA): New variable. (CLIBS): Include LIBLZMA. (SFILES): Mention minidebug.c. (COMMON_OBS): Mention minidebug.o. * symfile.c (read_symbols): New function. (syms_from_objfile, reread_symbols): Call it. * symfile.h (find_separate_debug_file_in_section): Declare. 2012-11-12 Tom Tromey <tromey@redhat.com> * gdb.texinfo (Separate Debug Section): New node. (GDB Files): Update. 2012-11-12 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.base/gnu-debugdata.exp: New file. * gdb.base/gnu-debugdata.c: New file. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9e7702d..864572c 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ # Where is expat? This will be empty if expat was not available. LIBEXPAT = @LIBEXPAT@ +# Where is lzma? This will be empty if lzma was not available. +LIBLZMA = @LIBLZMA@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ # LIBIBERTY appears twice on purpose. CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ - $(LIBEXPAT) \ + $(LIBEXPAT) $(LIBLZMA) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inline-frame.c \ interps.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ - language.c linespec.c \ + language.c linespec.c minidebug.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ filesystem.o \ inf-child.o \ interps.o \ + minidebug.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ diff --git a/gdb/NEWS b/gdb/NEWS index 4a1988d..0c84008 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -70,6 +70,11 @@ py [command] containing the absolute file name when GDB can determine it and source has been requested. +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. + You must have the LZMA library available when configuring GDB for this + feature to be enabled. For more information, see: + http://fedoraproject.org/wiki/Features/MiniDebugInfo + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/configure.ac b/gdb/configure.ac index f0b7df3..c751c2d 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2056,6 +2056,27 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ce5415d..9d03aad 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15787,6 +15787,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* Separate Debug Section:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -16712,6 +16713,44 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node Separate Debug Section +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This section holds an +LZMA-compressed object and is used to supply extra symbols for +backtraces. @value{GDBN} has support for this extension. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} diff --git a/gdb/minidebug.c b/gdb/minidebug.c new file mode 100644 index 0000000..8e1362f --- /dev/null +++ b/gdb/minidebug.c @@ -0,0 +1,284 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include <lzma.h> + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/gdb/symfile.c b/gdb/symfile.c index 55af541..6a2fc89 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + if (!objfile_has_partial_symbols (objfile)) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -2601,14 +2619,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bb75c18..223f874 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c new file mode 100644 index 0000000..b8b7e8a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 <signal.h> + +static int +debugdata_function (void) +{ + return raise (SIGSEGV) + 1; +} + +int +main (void) +{ + return debugdata_function () + 1; +} diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp new file mode 100644 index 0000000..2b304f1 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -0,0 +1,97 @@ +# Copyright 2012 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/>. + +standard_testfile + +if {[is_remote host]} { + return 0 +} + +if [build_executable ${testfile}.exp $testfile] { + return -1 +} + +proc run { test cmdline } { + verbose "cmdline is $cmdline" + set result [catch "exec $cmdline" output] + verbose "result is $result" + verbose "output is $output" + if {$result == 0} { + pass $test + return 0 + } else { + fail $test + return -1 + } +} + +set strip_program [transform strip] +set nm_program [transform nm] + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. +file delete -- ${binfile}.dynsyms +if [run "nm -D" "[transform nm] -D ${binfile} --format=posix --defined-only | awk \\{print\\ \\\$1\\} | sort > ${binfile}.dynsyms"] { + return -1 +} + +# Extract all the text (i.e. function) symbols from the debuginfo. +file delete -- ${binfile}.funcsyms +if [run "nm" "[transform nm] ${binfile} --format=posix --defined-only | awk \\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\} | sort > ${binfile}.funcsyms"] { + return -1 +} + +# Keep all the function symbols not already in the dynamic symbol +# table. +file delete -- ${binfile}.keep_symbols +if [run "comm" "comm -13 ${binfile}.dynsyms ${binfile}.funcsyms > ${binfile}.keep_symbols"] { + return -1 +} + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +file delete -- ${binfile}.mini_debuginfo +if [run "objcopy 1" "[transform objcopy] -S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"] { + return -1 +} + +# GDB specific - we do not have split executable in advance. +file delete -- ${binfile}.strip +if [run "strip" "[transform strip] --strip-all -o ${binfile}.strip ${binfile}"] { + return -1 +} + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +file delete -- ${binfile}.mini_debuginfo.xz +if [run "xz" "xz ${binfile}.mini_debuginfo"] { + return -1 +} +file delete -- ${binfile}.test +if [run "objcopy 2" "[transform objcopy] --add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"] { + return -1 +} + +clean_restart "$testfile.strip" + +gdb_test "p debugdata_function" \ + {No symbol table is loaded\. Use the "file" command\.} \ + "no symtab" + +clean_restart "$testfile.test" + +gdb_test "p debugdata_function" \ + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ + "have symtab" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-12 16:28 ` Tom Tromey @ 2012-11-13 18:36 ` Tom Tromey 2012-11-13 18:42 ` Eli Zaretskii 2012-11-13 19:12 ` Pedro Alves 0 siblings, 2 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-13 18:36 UTC (permalink / raw) To: gdb-patches Tom> Here is a new version of the patch. Here is another new version. This one fixes up the test suite for remote host testing, thanks again Pedro. This one also adds some more documentation. A new doc review is needed. Tom 2012-11-12 Alexander Larsson <alexl@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention mini debuginfo feature. * minidebug.c: New file. * configure.ac: Check for lzma. * configure, config.in: Rebuild. * Makefile.in (LIBLZMA): New variable. (CLIBS): Include LIBLZMA. (SFILES): Mention minidebug.c. (COMMON_OBS): Mention minidebug.o. * symfile.c (read_symbols): New function. (syms_from_objfile, reread_symbols): Call it. * symfile.h (find_separate_debug_file_in_section): Declare. 2012-11-12 Tom Tromey <tromey@redhat.com> * gdb.texinfo (Separate Debug Section): New node. (GDB Files): Update. 2012-11-12 Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.base/gnu-debugdata.exp: New file. * gdb.base/gnu-debugdata.c: New file. * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9e7702d..864572c 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ # Where is expat? This will be empty if expat was not available. LIBEXPAT = @LIBEXPAT@ +# Where is lzma? This will be empty if lzma was not available. +LIBLZMA = @LIBLZMA@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ # LIBIBERTY appears twice on purpose. CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ - $(LIBEXPAT) \ + $(LIBEXPAT) $(LIBLZMA) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inline-frame.c \ interps.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ - language.c linespec.c \ + language.c linespec.c minidebug.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ filesystem.o \ inf-child.o \ interps.o \ + minidebug.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ diff --git a/gdb/NEWS b/gdb/NEWS index 739a7b3..03ce548 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -91,6 +91,11 @@ show print type typedefs containing the absolute file name when GDB can determine it and source has been requested. +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. + You must have the LZMA library available when configuring GDB for this + feature to be enabled. For more information, see: + http://fedoraproject.org/wiki/Features/MiniDebugInfo + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/configure.ac b/gdb/configure.ac index f0b7df3..c751c2d 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2056,6 +2056,27 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 86cfe8e..d04566e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* Separate Debug Section:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -16790,6 +16791,55 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node Separate Debug Section +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This section holds an +LZMA-compressed object and is used to supply extra symbols for +backtraces. + +The intent of this section is to provide extra minimal debugging +information for use in simple backtraces. It is not intended to be a +replacement for full separate debugging information (@pxref{Separate +Debug Files}). The example below shows the intended use; however, +@value{GDBN} does not currently put restrictions on what sort of +debugging information might be included in the section. + +@value{GDBN} has support for this extension. If the section exists, +then it is used provided that no other source of debugging information +can be found, and that @value{GDBN} was configured with LZMA support. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} diff --git a/gdb/minidebug.c b/gdb/minidebug.c new file mode 100644 index 0000000..8e1362f --- /dev/null +++ b/gdb/minidebug.c @@ -0,0 +1,284 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include <lzma.h> + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/gdb/symfile.c b/gdb/symfile.c index 55af541..6a2fc89 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + if (!objfile_has_partial_symbols (objfile)) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -2601,14 +2619,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bb75c18..223f874 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c new file mode 100644 index 0000000..b8b7e8a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 <signal.h> + +static int +debugdata_function (void) +{ + return raise (SIGSEGV) + 1; +} + +int +main (void) +{ + return debugdata_function () + 1; +} diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp new file mode 100644 index 0000000..d659db0 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -0,0 +1,152 @@ +# Copyright 2012 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/>. + +standard_testfile + +if {[is_remote host]} { + return 0 +} + +if [build_executable ${testfile}.exp $testfile] { + return -1 +} + +# A wrapper for 'remote_exec host' that passes or fails a test. +# Returns 0 if all went well, nonzero on failure. +# TEST is the name of the test, other arguments are as for +# remote_exec. +proc run {test program args} { + verbose -log "cmdline is remote_exec host $program $args" + # remote_exec doesn't work properly if the output is set but the + # input is the empty string -- so replace an empty input with + # /dev/null. + if {[llength $args] > 1 && [lindex $args 1] == ""} { + set args [lreplace $args 1 1 "/dev/null"] + } + set result [eval remote_exec host [list $program] $args] + verbose "result is $result" + lassign $result status output + if {$status == 0} { + pass $test + return 0 + } else { + fail $test + return -1 + } +} + +set pipeline_counter 0 + +# Run a pipeline of processes through 'run'. +# TEST is the base name of the test, it is modified and passed to 'run'. +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. +# It is passed to 'run'. However, before being passed, if input and output +# files are not specified in the list, then this proc provides them. +# Each program in the pipeline takes its input from the previous +# program's output. +proc pipeline {test args} { + global pipeline_counter + + set input_file {} + foreach arglist $args { + verbose -log "raw args are $arglist" + lassign $arglist program arguments input output + + if {$input == ""} { + set input $input_file + } + if {$output == ""} { + set output [standard_output_file pipe.[pid].$pipeline_counter] + incr pipeline_counter + } + verbose -log "cooked args are [list $program $arguments $input $output]" + + if {[run "$test - invoke $program" $program $arguments \ + $input $output]} { + return -1 + } + + set input_file $output + } + return 0 +} + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. +remote_file host delete ${binfile}.dynsyms +if {[pipeline "nm -D" \ + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ + [list awk "\\{print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.dynsyms"]]} { + return -1 +} + +# Extract all the text (i.e. function) symbols from the debuginfo. +remote_file host delete ${binfile}.funcsyms +if {[pipeline "nm" \ + [list [transform nm] "${binfile} --format=posix --defined-only"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.funcsyms"]]} { + return -1 +} + +# Keep all the function symbols not already in the dynamic symbol +# table. +remote_file host delete ${binfile}.keep_symbols +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ + "${binfile}.keep_symbols"]} { + return -1 +} + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +remote_file host delete ${binfile}.mini_debuginfo +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { + return -1 +} + +# GDB specific - we do not have split executable in advance. +remote_file host delete ${binfile}.strip +if {[run "strip" [transform strip] \ + "--strip-all -o ${binfile}.strip ${binfile}"]} { + return -1 +} + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +remote_file host delete ${binfile}.mini_debuginfo.xz +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { + return -1 +} +remote_file host delete ${binfile}.test +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { + return -1 +} + +clean_restart "$testfile.strip" + +gdb_test "p debugdata_function" \ + {No symbol table is loaded\. Use the "file" command\.} \ + "no symtab" + +clean_restart "$testfile.test" + +if {$gdb_file_cmd_debug_info == "lzma"} { + unsupported "LZMA support not available in this gdb" +} else { + gdb_test_multiple "p debugdata_function" \ + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ + "have symtab" +} diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 16e8b54..00d156d 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1278,6 +1278,8 @@ proc default_gdb_exit {} { # # debug file was loaded successfully and has debug information # nodebug file was loaded successfully and has no debug information +# lzma file was loaded, .gnu_debugdata found, but no LZMA support +# compiled in # fail file was not loaded # # I tried returning this information as part of the return value, @@ -1325,6 +1327,11 @@ proc gdb_file_cmd { arg } { send_gdb "file $arg\n" gdb_expect 120 { + -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" { + verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available" + set gdb_file_cmd_debug_info "lzma" + return 0 + } -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into $GDB with no debugging symbols" set gdb_file_cmd_debug_info "nodebug" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 18:36 ` Tom Tromey @ 2012-11-13 18:42 ` Eli Zaretskii 2012-11-13 19:12 ` Pedro Alves 1 sibling, 0 replies; 42+ messages in thread From: Eli Zaretskii @ 2012-11-13 18:42 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > From: Tom Tromey <tromey@redhat.com> > Date: Tue, 13 Nov 2012 11:35:44 -0700 > > Tom> Here is a new version of the patch. > > Here is another new version. > > This one fixes up the test suite for remote host testing, thanks again > Pedro. > > This one also adds some more documentation. A new doc review is needed. The documentation parts are OK. Thanks. ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 18:36 ` Tom Tromey 2012-11-13 18:42 ` Eli Zaretskii @ 2012-11-13 19:12 ` Pedro Alves 2012-11-13 20:57 ` Tom Tromey 1 sibling, 1 reply; 42+ messages in thread From: Pedro Alves @ 2012-11-13 19:12 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 11/13/2012 06:35 PM, Tom Tromey wrote: > index 86cfe8e..d04566e 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell > @menu > * Files:: Commands to specify files > * Separate Debug Files:: Debugging information in separate files > +* Separate Debug Section:: Debugging information in a special section This is likely a very minor issue, but, on "Separate Debug Section": I understand that "Separate" came from this being a reuse of the "separate debug file" idea, but OTOH I find that terminology confusing (which makes me think first-time readers unaware of the concept might too on first grance). The debug info is is actually bolted inside the main binary, which is the opposite of separate. :-) Maybe: "Debug File Embedded in Special Section" "Separate Debug File Embedded in Special Section" Are we going to call this "MiniDebugInfo" going forward (as the minidebug.c file spells it)? Would it be a good idea to put a "a.k.a. MiniDebugInfo" in the docs? > * Index Files:: Index files speed up GDB > * Symbol Errors:: Errors reading symbol files > * Data Files:: GDB data files On 11/13/2012 06:35 PM, Tom Tromey wrote: > +if {[is_remote host]} { > + return 0 > +} This is no longer necessary. Otherwise I have no further comments. Thanks. -- Pedro Alves ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 19:12 ` Pedro Alves @ 2012-11-13 20:57 ` Tom Tromey 2012-11-14 16:13 ` Tom Tromey 0 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-13 20:57 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches >>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: Pedro> Are we going to call this "MiniDebugInfo" going forward (as the Pedro> minidebug.c file spells it)? Would it be a good idea to put a Pedro> "a.k.a. MiniDebugInfo" in the docs? Yeah, good idea. I did this and I renamed the node to "MiniDebugInfo". >> +if {[is_remote host]} { >> + return 0 >> +} Pedro> This is no longer necessary. Whoops. Here's the revised. Tom 2012-11-12 Alexander Larsson <alexl@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention mini debuginfo feature. * minidebug.c: New file. * configure.ac: Check for lzma. * configure, config.in: Rebuild. * Makefile.in (LIBLZMA): New variable. (CLIBS): Include LIBLZMA. (SFILES): Mention minidebug.c. (COMMON_OBS): Mention minidebug.o. * symfile.c (read_symbols): New function. (syms_from_objfile, reread_symbols): Call it. * symfile.h (find_separate_debug_file_in_section): Declare. 2012-11-12 Tom Tromey <tromey@redhat.com> * gdb.texinfo (MiniDebugInfo): New node. (GDB Files): Update. 2012-11-12 Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.base/gnu-debugdata.exp: New file. * gdb.base/gnu-debugdata.c: New file. * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9e7702d..864572c 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ # Where is expat? This will be empty if expat was not available. LIBEXPAT = @LIBEXPAT@ +# Where is lzma? This will be empty if lzma was not available. +LIBLZMA = @LIBLZMA@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ # LIBIBERTY appears twice on purpose. CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ - $(LIBEXPAT) \ + $(LIBEXPAT) $(LIBLZMA) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inline-frame.c \ interps.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ - language.c linespec.c \ + language.c linespec.c minidebug.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ filesystem.o \ inf-child.o \ interps.o \ + minidebug.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ diff --git a/gdb/NEWS b/gdb/NEWS index 739a7b3..03ce548 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -91,6 +91,11 @@ show print type typedefs containing the absolute file name when GDB can determine it and source has been requested. +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. + You must have the LZMA library available when configuring GDB for this + feature to be enabled. For more information, see: + http://fedoraproject.org/wiki/Features/MiniDebugInfo + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/config.in b/gdb/config.in index 0f795c6..3db2d46 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -195,6 +195,9 @@ /* Define to 1 if you have the `libiconvlist' function. */ #undef HAVE_LIBICONVLIST +/* Define if you have the lzma library. */ +#undef HAVE_LIBLZMA + /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM diff --git a/gdb/configure b/gdb/configure index 68ee707..4cddd2f 100755 --- a/gdb/configure +++ b/gdb/configure @@ -641,6 +641,9 @@ TCL_VERSION WIN32LDAPP GUI_CFLAGS_X LIBGUI +LTLIBLZMA +LIBLZMA +HAVE_LIBLZMA WIN32LIBS SER_HARDWIRE WERROR_CFLAGS @@ -808,6 +811,8 @@ with_system_gdbinit enable_werror enable_build_warnings enable_gdb_build_warnings +with_lzma +with_liblzma_prefix with_tcl with_tk with_x @@ -1521,6 +1526,9 @@ Optional Packages: --with-sysroot[=DIR] search for usr/lib et al within DIR --with-system-gdbinit=PATH automatically load a system-wide gdbinit file + --with-lzma support lzma compression (auto/yes/no) + --with-liblzma-prefix[=DIR] search for liblzma in DIR/include and DIR/lib + --without-liblzma-prefix don't search for liblzma in includedir and libdir --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tk directory containing tk configuration (tkConfig.sh) --with-x use the X Window System @@ -12661,6 +12669,494 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + +# Check whether --with-lzma was given. +if test "${with_lzma+set}" = set; then : + withval=$with_lzma; +else + with_lzma=auto +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use lzma" >&5 +$as_echo_n "checking whether to use lzma... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lzma" >&5 +$as_echo "$with_lzma" >&6; } + + if test "${with_lzma}" != no; then + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-liblzma-prefix was given. +if test "${with_liblzma_prefix+set}" = set; then : + withval=$with_liblzma_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi + +fi + + LIBLZMA= + LTLIBLZMA= + INCLZMA= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='lzma ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBLZMA="${LTLIBLZMA}${LTLIBLZMA:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBLZMA; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBLZMA="${LTLIBLZMA}${LTLIBLZMA:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBLZMA; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$found_so" + else + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$found_a" + else + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCLZMA; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCLZMA="${INCLZMA}${INCLZMA:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBLZMA; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBLZMA; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBLZMA="${LTLIBLZMA}${LTLIBLZMA:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$dep" + LTLIBLZMA="${LTLIBLZMA}${LTLIBLZMA:+ }$dep" + ;; + esac + done + fi + else + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }-l$name" + LTLIBLZMA="${LTLIBLZMA}${LTLIBLZMA:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBLZMA="${LIBLZMA}${LIBLZMA:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBLZMA="${LTLIBLZMA}${LTLIBLZMA:+ }-R$found_dir" + done + fi + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCLZMA; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for liblzma" >&5 +$as_echo_n "checking for liblzma... " >&6; } +if test "${ac_cv_liblzma+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIBLZMA" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "lzma.h" +int +main () +{ +lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_liblzma=yes +else + ac_cv_liblzma=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_liblzma" >&5 +$as_echo "$ac_cv_liblzma" >&6; } + if test "$ac_cv_liblzma" = yes; then + HAVE_LIBLZMA=yes + +$as_echo "#define HAVE_LIBLZMA 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with liblzma" >&5 +$as_echo_n "checking how to link with liblzma... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBLZMA" >&5 +$as_echo "$LIBLZMA" >&6; } + else + HAVE_LIBLZMA=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBLZMA= + LTLIBLZMA= + fi + + + + + + + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + as_fn_error "missing liblzma for --with-lzma" "$LINENO" 5 + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" diff --git a/gdb/configure.ac b/gdb/configure.ac index f0b7df3..c751c2d 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2056,6 +2056,27 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 86cfe8e..224bdbf 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* MiniDebugInfo:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -16790,6 +16791,55 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node MiniDebugInfo +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This feature is called +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and +is used to supply extra symbols for backtraces. + +The intent of this section is to provide extra minimal debugging +information for use in simple backtraces. It is not intended to be a +replacement for full separate debugging information (@pxref{Separate +Debug Files}). The example below shows the intended use; however, +@value{GDBN} does not currently put restrictions on what sort of +debugging information might be included in the section. + +@value{GDBN} has support for this extension. If the section exists, +then it is used provided that no other source of debugging information +can be found, and that @value{GDBN} was configured with LZMA support. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} diff --git a/gdb/minidebug.c b/gdb/minidebug.c new file mode 100644 index 0000000..8e1362f --- /dev/null +++ b/gdb/minidebug.c @@ -0,0 +1,284 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include <lzma.h> + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/gdb/symfile.c b/gdb/symfile.c index 55af541..6a2fc89 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + if (!objfile_has_partial_symbols (objfile)) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -2601,14 +2619,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bb75c18..223f874 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c new file mode 100644 index 0000000..b8b7e8a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 <signal.h> + +static int +debugdata_function (void) +{ + return raise (SIGSEGV) + 1; +} + +int +main (void) +{ + return debugdata_function () + 1; +} diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp new file mode 100644 index 0000000..eaf1ed1 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -0,0 +1,148 @@ +# Copyright 2012 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/>. + +standard_testfile + +if [build_executable ${testfile}.exp $testfile] { + return -1 +} + +# A wrapper for 'remote_exec host' that passes or fails a test. +# Returns 0 if all went well, nonzero on failure. +# TEST is the name of the test, other arguments are as for +# remote_exec. +proc run {test program args} { + verbose -log "cmdline is remote_exec host $program $args" + # remote_exec doesn't work properly if the output is set but the + # input is the empty string -- so replace an empty input with + # /dev/null. + if {[llength $args] > 1 && [lindex $args 1] == ""} { + set args [lreplace $args 1 1 "/dev/null"] + } + set result [eval remote_exec host [list $program] $args] + verbose "result is $result" + lassign $result status output + if {$status == 0} { + pass $test + return 0 + } else { + fail $test + return -1 + } +} + +set pipeline_counter 0 + +# Run a pipeline of processes through 'run'. +# TEST is the base name of the test, it is modified and passed to 'run'. +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. +# It is passed to 'run'. However, before being passed, if input and output +# files are not specified in the list, then this proc provides them. +# Each program in the pipeline takes its input from the previous +# program's output. +proc pipeline {test args} { + global pipeline_counter + + set input_file {} + foreach arglist $args { + verbose -log "raw args are $arglist" + lassign $arglist program arguments input output + + if {$input == ""} { + set input $input_file + } + if {$output == ""} { + set output [standard_output_file pipe.[pid].$pipeline_counter] + incr pipeline_counter + } + verbose -log "cooked args are [list $program $arguments $input $output]" + + if {[run "$test - invoke $program" $program $arguments \ + $input $output]} { + return -1 + } + + set input_file $output + } + return 0 +} + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. +remote_file host delete ${binfile}.dynsyms +if {[pipeline "nm -D" \ + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ + [list awk "\\{print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.dynsyms"]]} { + return -1 +} + +# Extract all the text (i.e. function) symbols from the debuginfo. +remote_file host delete ${binfile}.funcsyms +if {[pipeline "nm" \ + [list [transform nm] "${binfile} --format=posix --defined-only"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.funcsyms"]]} { + return -1 +} + +# Keep all the function symbols not already in the dynamic symbol +# table. +remote_file host delete ${binfile}.keep_symbols +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ + "${binfile}.keep_symbols"]} { + return -1 +} + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +remote_file host delete ${binfile}.mini_debuginfo +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { + return -1 +} + +# GDB specific - we do not have split executable in advance. +remote_file host delete ${binfile}.strip +if {[run "strip" [transform strip] \ + "--strip-all -o ${binfile}.strip ${binfile}"]} { + return -1 +} + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +remote_file host delete ${binfile}.mini_debuginfo.xz +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { + return -1 +} +remote_file host delete ${binfile}.test +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { + return -1 +} + +clean_restart "$testfile.strip" + +gdb_test "p debugdata_function" \ + {No symbol table is loaded\. Use the "file" command\.} \ + "no symtab" + +clean_restart "$testfile.test" + +if {$gdb_file_cmd_debug_info == "lzma"} { + unsupported "LZMA support not available in this gdb" +} else { + gdb_test_multiple "p debugdata_function" \ + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ + "have symtab" +} diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 16e8b54..00d156d 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1278,6 +1278,8 @@ proc default_gdb_exit {} { # # debug file was loaded successfully and has debug information # nodebug file was loaded successfully and has no debug information +# lzma file was loaded, .gnu_debugdata found, but no LZMA support +# compiled in # fail file was not loaded # # I tried returning this information as part of the return value, @@ -1325,6 +1327,11 @@ proc gdb_file_cmd { arg } { send_gdb "file $arg\n" gdb_expect 120 { + -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" { + verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available" + set gdb_file_cmd_debug_info "lzma" + return 0 + } -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into $GDB with no debugging symbols" set gdb_file_cmd_debug_info "nodebug" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 20:57 ` Tom Tromey @ 2012-11-14 16:13 ` Tom Tromey 2012-11-14 16:19 ` Pedro Alves 2012-11-14 19:37 ` Doug Evans 0 siblings, 2 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-14 16:13 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Tom> Here's the revised. I caught one little problem -- I had used gdb_test_multiple in an earlier revision and forgot to change it back. This lead to a test failure. Sigh. This version also changes some "verbose -log" calls back to "verbose", to avoid cluttering up the .log file unnecessarily. Finally, I was curious about the test coverage; this pointed out that the _close function was not being tested, so I added a test for that. There are still a few spots in the new file that aren't covered, but mostly errors, and I'm not as interested in testing all those. Tom 2012-11-14 Alexander Larsson <alexl@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention mini debuginfo feature. * minidebug.c: New file. * configure.ac: Check for lzma. * configure, config.in: Rebuild. * Makefile.in (LIBLZMA): New variable. (CLIBS): Include LIBLZMA. (SFILES): Mention minidebug.c. (COMMON_OBS): Mention minidebug.o. * symfile.c (read_symbols): New function. (syms_from_objfile, reread_symbols): Call it. * symfile.h (find_separate_debug_file_in_section): Declare. 2012-11-14 Tom Tromey <tromey@redhat.com> * gdb.texinfo (MiniDebugInfo): New node. (GDB Files): Update. 2012-11-14 Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.base/gnu-debugdata.exp: New file. * gdb.base/gnu-debugdata.c: New file. * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. (gdb_unload): Return 0 on success. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9e7702d..864572c 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ # Where is expat? This will be empty if expat was not available. LIBEXPAT = @LIBEXPAT@ +# Where is lzma? This will be empty if lzma was not available. +LIBLZMA = @LIBLZMA@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ # LIBIBERTY appears twice on purpose. CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ - $(LIBEXPAT) \ + $(LIBEXPAT) $(LIBLZMA) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inline-frame.c \ interps.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ - language.c linespec.c \ + language.c linespec.c minidebug.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ filesystem.o \ inf-child.o \ interps.o \ + minidebug.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ diff --git a/gdb/NEWS b/gdb/NEWS index 739a7b3..03ce548 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -91,6 +91,11 @@ show print type typedefs containing the absolute file name when GDB can determine it and source has been requested. +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. + You must have the LZMA library available when configuring GDB for this + feature to be enabled. For more information, see: + http://fedoraproject.org/wiki/Features/MiniDebugInfo + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/configure.ac b/gdb/configure.ac index f0b7df3..c751c2d 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2056,6 +2056,27 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 86cfe8e..224bdbf 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* MiniDebugInfo:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -16790,6 +16791,55 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node MiniDebugInfo +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This feature is called +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and +is used to supply extra symbols for backtraces. + +The intent of this section is to provide extra minimal debugging +information for use in simple backtraces. It is not intended to be a +replacement for full separate debugging information (@pxref{Separate +Debug Files}). The example below shows the intended use; however, +@value{GDBN} does not currently put restrictions on what sort of +debugging information might be included in the section. + +@value{GDBN} has support for this extension. If the section exists, +then it is used provided that no other source of debugging information +can be found, and that @value{GDBN} was configured with LZMA support. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} diff --git a/gdb/minidebug.c b/gdb/minidebug.c new file mode 100644 index 0000000..8e1362f --- /dev/null +++ b/gdb/minidebug.c @@ -0,0 +1,284 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include <lzma.h> + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/gdb/symfile.c b/gdb/symfile.c index 55af541..6a2fc89 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + if (!objfile_has_partial_symbols (objfile)) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -2601,14 +2619,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bb75c18..223f874 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c new file mode 100644 index 0000000..b8b7e8a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 <signal.h> + +static int +debugdata_function (void) +{ + return raise (SIGSEGV) + 1; +} + +int +main (void) +{ + return debugdata_function () + 1; +} diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp new file mode 100644 index 0000000..f876309 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -0,0 +1,157 @@ +# Copyright 2012 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/>. + +standard_testfile + +if [build_executable ${testfile}.exp $testfile] { + return -1 +} + +# A wrapper for 'remote_exec host' that passes or fails a test. +# Returns 0 if all went well, nonzero on failure. +# TEST is the name of the test, other arguments are as for +# remote_exec. +proc run {test program args} { + verbose "cmdline is remote_exec host $program $args" + # remote_exec doesn't work properly if the output is set but the + # input is the empty string -- so replace an empty input with + # /dev/null. + if {[llength $args] > 1 && [lindex $args 1] == ""} { + set args [lreplace $args 1 1 "/dev/null"] + } + set result [eval remote_exec host [list $program] $args] + verbose "result is $result" + lassign $result status output + if {$status == 0} { + pass $test + return 0 + } else { + fail $test + return -1 + } +} + +set pipeline_counter 0 + +# Run a pipeline of processes through 'run'. +# TEST is the base name of the test, it is modified and passed to 'run'. +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. +# It is passed to 'run'. However, before being passed, if input and output +# files are not specified in the list, then this proc provides them. +# Each program in the pipeline takes its input from the previous +# program's output. +proc pipeline {test args} { + global pipeline_counter + + set input_file {} + foreach arglist $args { + verbose "raw args are $arglist" + lassign $arglist program arguments input output + + if {$input == ""} { + set input $input_file + } + if {$output == ""} { + set output [standard_output_file pipe.[pid].$pipeline_counter] + incr pipeline_counter + } + verbose "cooked args are [list $program $arguments $input $output]" + + if {[run "$test - invoke $program" $program $arguments \ + $input $output]} { + return -1 + } + + set input_file $output + } + return 0 +} + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. +remote_file host delete ${binfile}.dynsyms +if {[pipeline "nm -D" \ + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ + [list awk "\\{print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.dynsyms"]]} { + return -1 +} + +# Extract all the text (i.e. function) symbols from the debuginfo. +remote_file host delete ${binfile}.funcsyms +if {[pipeline "nm" \ + [list [transform nm] "${binfile} --format=posix --defined-only"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.funcsyms"]]} { + return -1 +} + +# Keep all the function symbols not already in the dynamic symbol +# table. +remote_file host delete ${binfile}.keep_symbols +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ + "${binfile}.keep_symbols"]} { + return -1 +} + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +remote_file host delete ${binfile}.mini_debuginfo +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { + return -1 +} + +# GDB specific - we do not have split executable in advance. +remote_file host delete ${binfile}.strip +if {[run "strip" [transform strip] \ + "--strip-all -o ${binfile}.strip ${binfile}"]} { + return -1 +} + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +remote_file host delete ${binfile}.mini_debuginfo.xz +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { + return -1 +} +remote_file host delete ${binfile}.test +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { + return -1 +} + +clean_restart "$testfile.strip" + +gdb_test "p debugdata_function" \ + {No symbol table is loaded\. Use the "file" command\.} \ + "no symtab" + +clean_restart "$testfile.test" + +if {$gdb_file_cmd_debug_info == "lzma"} { + unsupported "LZMA support not available in this gdb" +} else { + gdb_test "p debugdata_function" \ + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ + "have symtab" +} + +# Be sure to test the 'close' method on the MiniDebugInfo BFD. +if {[gdb_unload]} { + fail "unload MiniDebugInfo" +} else { + pass "unload MiniDebugInfo" +} + +gdb_exit diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 16e8b54..781ccc8 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -128,6 +128,7 @@ proc gdb_version { } { # # gdb_unload -- unload a file if one is loaded +# Return 0 on success, -1 on error. # proc gdb_unload {} { @@ -152,6 +153,7 @@ proc gdb_unload {} { return -1 } } + return 0 } # Many of the tests depend on setting breakpoints at various places and @@ -1278,6 +1280,8 @@ proc default_gdb_exit {} { # # debug file was loaded successfully and has debug information # nodebug file was loaded successfully and has no debug information +# lzma file was loaded, .gnu_debugdata found, but no LZMA support +# compiled in # fail file was not loaded # # I tried returning this information as part of the return value, @@ -1325,6 +1329,11 @@ proc gdb_file_cmd { arg } { send_gdb "file $arg\n" gdb_expect 120 { + -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" { + verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available" + set gdb_file_cmd_debug_info "lzma" + return 0 + } -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into $GDB with no debugging symbols" set gdb_file_cmd_debug_info "nodebug" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-14 16:13 ` Tom Tromey @ 2012-11-14 16:19 ` Pedro Alves 2012-11-14 16:59 ` Tom Tromey 2012-11-14 19:37 ` Doug Evans 1 sibling, 1 reply; 42+ messages in thread From: Pedro Alves @ 2012-11-14 16:19 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 11/14/2012 04:13 PM, Tom Tromey wrote: > Finally, I was curious about the test coverage; this pointed out that > the _close function was not being tested, so I added a test for that. That's awesome. Makes me wonder about adding a coverage section to the test case cookbook in the wiki. -- Pedro Alves ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-14 16:19 ` Pedro Alves @ 2012-11-14 16:59 ` Tom Tromey 0 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-14 16:59 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches >>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: Pedro> On 11/14/2012 04:13 PM, Tom Tromey wrote: >> Finally, I was curious about the test coverage; this pointed out that >> the _close function was not being tested, so I added a test for that. Pedro> That's awesome. Makes me wonder about adding a coverage section to Pedro> the test case cookbook in the wiki. I'll write something. I was curious if we could automate this, but it seems hard to make it work robustly. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-14 16:13 ` Tom Tromey 2012-11-14 16:19 ` Pedro Alves @ 2012-11-14 19:37 ` Doug Evans 2012-11-14 22:12 ` Joel Brobecker ` (2 more replies) 1 sibling, 3 replies; 42+ messages in thread From: Doug Evans @ 2012-11-14 19:37 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, gdb-patches Tom Tromey writes: > Tom> Here's the revised. > > I caught one little problem -- I had used gdb_test_multiple in an > earlier revision and forgot to change it back. This lead to a test > failure. Sigh. > > This version also changes some "verbose -log" calls back to "verbose", > to avoid cluttering up the .log file unnecessarily. > > Finally, I was curious about the test coverage; this pointed out that > the _close function was not being tested, so I added a test for that. > There are still a few spots in the new file that aren't covered, but > mostly errors, and I'm not as interested in testing all those. > > Tom > > 2012-11-14 Alexander Larsson <alexl@redhat.com> > Jan Kratochvil <jan.kratochvil@redhat.com> > Tom Tromey <tromey@redhat.com> > > * NEWS: Mention mini debuginfo feature. > * minidebug.c: New file. > * configure.ac: Check for lzma. > * configure, config.in: Rebuild. > * Makefile.in (LIBLZMA): New variable. > (CLIBS): Include LIBLZMA. > (SFILES): Mention minidebug.c. > (COMMON_OBS): Mention minidebug.o. > * symfile.c (read_symbols): New function. > (syms_from_objfile, reread_symbols): Call it. > * symfile.h (find_separate_debug_file_in_section): Declare. > > 2012-11-14 Tom Tromey <tromey@redhat.com> > > * gdb.texinfo (MiniDebugInfo): New node. > (GDB Files): Update. > > 2012-11-14 Jan Kratochvil <jan.kratochvil@redhat.com> > Tom Tromey <tromey@redhat.com> > > * gdb.base/gnu-debugdata.exp: New file. > * gdb.base/gnu-debugdata.c: New file. > * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. > (gdb_unload): Return 0 on success. Hi. A couple of comments. 1) Being more of a minimalist when it comes to adding new stuff, and applying "It's easier to relax restrictions than impose them after the fact." it would be easy enough to restrict the section to being an (lzma-compressed) ELF file (and equally easy to relax the restriction if someone ever presented a compelling reason to support it). Sure, we *can* support COFF, etc. but that doesn't, to me, mean we *should*. Does Redhat have a *formal* spec of .gnu_debugdata that says COFF, etc. is supported. [If that's the case then my point is moot, but I couldn't find any such formal spec.] 2) Can you add something like the following to the docs? This section is an LZMA compressed ELF file containing the standard ELF symbol and DWARF sections. It needn't, but may, contain full debug info. The intent is that it contains the desired subset of debug info that makes things like backtracing work without making the file too large. The point being the current docs say what .gnu_debugdata *does*, but it doesn't formally and completely say what it *is*. "LZMA-compressed object" leaves me guessing too much at the details. By the way, strip -g should remove .gnu_debugdata. I only skimmed subject lines of recent messages to binutils@ to see if a patch has been submitted, and I just checked cvs head. > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 86cfe8e..224bdbf 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell > @menu > * Files:: Commands to specify files > * Separate Debug Files:: Debugging information in separate files > +* MiniDebugInfo:: Debugging information in a special section > * Index Files:: Index files speed up GDB > * Symbol Errors:: Errors reading symbol files > * Data Files:: GDB data files > @@ -16790,6 +16791,55 @@ gnu_debuglink_crc32 (unsigned long crc, > @noindent > This computation does not apply to the ``build ID'' method. > > +@node MiniDebugInfo > +@section Debugging information in a special section > +@cindex separate debug sections > +@cindex @samp{.gnu_debugdata} section > + > +Some systems ship pre-built executables and libraries that have a > +special @samp{.gnu_debugdata} section. This feature is called > +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and > +is used to supply extra symbols for backtraces. > + > +The intent of this section is to provide extra minimal debugging > +information for use in simple backtraces. It is not intended to be a > +replacement for full separate debugging information (@pxref{Separate > +Debug Files}). The example below shows the intended use; however, > +@value{GDBN} does not currently put restrictions on what sort of > +debugging information might be included in the section. > + > +@value{GDBN} has support for this extension. If the section exists, > +then it is used provided that no other source of debugging information > +can be found, and that @value{GDBN} was configured with LZMA support. > + > +This section can be easily created using @command{objcopy} and other > +standard utilities: > + > +@smallexample > +# Extract the dynamic symbols from the main binary, there is no need > +# to also have these in the normal symbol table > +nm -D @var{binary} --format=posix --defined-only \ > + | awk '@{ print $1 @}' | sort > dynsyms > + > +# Extract all the text (i.e. function) symbols from the debuginfo . > +nm @var{binary} --format=posix --defined-only \ > + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ > + | sort > funcsyms > + > +# Keep all the function symbols not already in the dynamic symbol > +# table. > +comm -13 dynsyms funcsyms > keep_symbols > + > +# Copy the full debuginfo, keeping only a minimal set of symbols and > +# removing some unnecessary sections. > +objcopy -S --remove-section .gdb_index --remove-section .comment \ > + --keep-symbols=keep_symbols @var{binary} mini_debuginfo > + > +# Inject the compressed data into the .gnu_debugdata section of the > +# original binary. > +xz mini_debuginfo > +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} > +@end smallexample ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-14 19:37 ` Doug Evans @ 2012-11-14 22:12 ` Joel Brobecker 2012-11-15 11:18 ` Pedro Alves 2012-11-16 20:04 ` Tom Tromey 2 siblings, 0 replies; 42+ messages in thread From: Joel Brobecker @ 2012-11-14 22:12 UTC (permalink / raw) To: Doug Evans; +Cc: Tom Tromey, Pedro Alves, gdb-patches > 1) Being more of a minimalist when it comes to adding new stuff, and > applying "It's easier to relax restrictions than impose them after the > fact." it would be easy enough to restrict the section to being an > (lzma-compressed) ELF file (and equally easy to relax the restriction > if someone ever presented a compelling reason to support it). Sure, > we *can* support COFF, etc. but that doesn't, to me, mean we *should*. > Does Redhat have a *formal* spec of .gnu_debugdata that says COFF, > etc. is supported. [If that's the case then my point is moot, but I > couldn't find any such formal spec.] I am still trying to understand exactly what you mean by the above. Sorry for being dense! can you clarify a bit? As said on IRC, it seems to me that you want to disable this feature on targets that use non-ELF object files (which would require some extra code just to make sure we activate this only if the object file is ELF). But our discussion on IRC seems to indicate that you're proposing something else... -- Joel ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-14 19:37 ` Doug Evans 2012-11-14 22:12 ` Joel Brobecker @ 2012-11-15 11:18 ` Pedro Alves 2012-11-16 19:51 ` Tom Tromey 2012-11-16 20:04 ` Tom Tromey 2 siblings, 1 reply; 42+ messages in thread From: Pedro Alves @ 2012-11-15 11:18 UTC (permalink / raw) To: Doug Evans; +Cc: Tom Tromey, Pedro Alves, gdb-patches On 14-11-2012 19:37, Doug Evans wrote: > 1) Being more of a minimalist when it comes to adding new stuff, and > applying "It's easier to relax restrictions than impose them after the fact." While in general I agree with this, > it would be easy enough to restrict the section to being an (lzma-compressed) > ELF file (and equally easy to relax the restriction if someone ever presented > a compelling reason to support it). Sure, we *can* support COFF, etc. but > that doesn't, to me, mean we *should*. > Does Redhat have a *formal* spec of .gnu_debugdata that says COFF, etc. is > supported. [If that's the case then my point is moot, > but I couldn't find any such formal spec.] I disagree with artificially making this ELF only. What you find stuffed in a .gnu_debugdata section is just another file that would otherwise be loadable by gdb if it was separate on the filesystem. IOW, stuffing the file as compressed binary blob into .gnu_debugdata is just a replacement for making the file really separate on the file system. There's really nothing container-specific (coff/elf,whatnot) in this. -- Pedro Alves ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-15 11:18 ` Pedro Alves @ 2012-11-16 19:51 ` Tom Tromey 2012-11-19 14:41 ` Pedro Alves 0 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-16 19:51 UTC (permalink / raw) To: Pedro Alves; +Cc: Doug Evans, gdb-patches >>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: Pedro> I disagree with artificially making this ELF only. What you find Pedro> stuffed in a .gnu_debugdata section is just another file that Pedro> would otherwise be loadable by gdb if it was separate on the Pedro> filesystem. IOW, stuffing the file as compressed binary blob Pedro> into .gnu_debugdata is just a replacement for making the file Pedro> really separate on the file system. There's really nothing Pedro> container-specific (coff/elf,whatnot) in this. What if we require the contents to have the same BFD flavour as the container? Like the appended. I think this might address Doug's critique -- not sure -- while retaining both some flexibility and some sanity. Really, though, nobody is going to use this outside of ELF. I think it mildly unlikely, though not impossible, that any distros outside the Fedora universe will even pick it up. Tom diff --git a/gdb/minidebug.c b/gdb/minidebug.c index 8e1362f..1b75ead 100644 --- a/gdb/minidebug.c +++ b/gdb/minidebug.c @@ -259,6 +259,9 @@ find_separate_debug_file_in_section (struct objfile *objfile) asection *section; bfd *abfd; + if (objfile->obfd == NULL) + return NULL; + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); if (section == NULL) return NULL; @@ -271,6 +274,14 @@ find_separate_debug_file_in_section (struct objfile *objfile) if (!bfd_check_format (abfd, bfd_object)) { + warning (_("Cannot parse .gnu_debugdata section; not a BFD object")); + gdb_bfd_unref (abfd); + return NULL; + } + + if (bfd_get_flavour (objfile->obfd) != bfd_get_flavour (abfd)) + { + warning (_("Cannot parse .gnu_debugdata section; wrong file format")); gdb_bfd_unref (abfd); return NULL; } ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-16 19:51 ` Tom Tromey @ 2012-11-19 14:41 ` Pedro Alves 2012-11-26 19:21 ` Tom Tromey 0 siblings, 1 reply; 42+ messages in thread From: Pedro Alves @ 2012-11-19 14:41 UTC (permalink / raw) To: Tom Tromey; +Cc: Doug Evans, gdb-patches On 11/16/2012 07:51 PM, Tom Tromey wrote: >>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: > > Pedro> I disagree with artificially making this ELF only. What you find > Pedro> stuffed in a .gnu_debugdata section is just another file that > Pedro> would otherwise be loadable by gdb if it was separate on the > Pedro> filesystem. IOW, stuffing the file as compressed binary blob > Pedro> into .gnu_debugdata is just a replacement for making the file > Pedro> really separate on the file system. There's really nothing > Pedro> container-specific (coff/elf,whatnot) in this. > > What if we require the contents to have the same BFD flavour as the > container? Do we spell out the same requirement for separate debug files? I still fail to see why we don't just describe this as what it is, not less nor more: exactly the same as separate debug file, but instead of being found as a separate file in the file system, it's tucked along inside the main binary. This is IMO the simplest way to document this, because from that perspective, it's not really anything that much new. If this view is not really correct, then we should document what is expected to not work in this mode compared to a real separate debug file. -- Pedro Alves ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-19 14:41 ` Pedro Alves @ 2012-11-26 19:21 ` Tom Tromey 2012-11-26 22:24 ` Andrew Pinski ` (2 more replies) 0 siblings, 3 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-26 19:21 UTC (permalink / raw) To: Pedro Alves; +Cc: Doug Evans, gdb-patches >>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: Pedro> Do we spell out the same requirement for separate debug files? I Pedro> still fail to see why we don't just describe this as what it is, Pedro> not less nor more: exactly the same as separate debug file, but Pedro> instead of being found as a separate file in the file system, Pedro> it's tucked along inside the main binary. Doug said off-list that he would be ok with what I was planning to put in. So, here is the final patch which I am committing. I removed the BFD flavour check and the corresponding paragraph from the manual. Built and regtested on x86-64 Fedora 16. Tom 2012-11-26 Alexander Larsson <alexl@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention mini debuginfo feature. * minidebug.c: New file. * configure.ac: Check for lzma. * configure, config.in: Rebuild. * Makefile.in (LIBLZMA): New variable. (CLIBS): Include LIBLZMA. (SFILES): Mention minidebug.c. (COMMON_OBS): Mention minidebug.o. * symfile.c (read_symbols): New function. (syms_from_objfile, reread_symbols): Call it. * symfile.h (find_separate_debug_file_in_section): Declare. 2012-11-26 Tom Tromey <tromey@redhat.com> * gdb.texinfo (MiniDebugInfo): New node. (GDB Files): Update. 2012-11-26 Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.base/gnu-debugdata.exp: New file. * gdb.base/gnu-debugdata.c: New file. * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. (gdb_unload): Return 0 on success. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index e9aeb0c..3dd7b85 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ # Where is expat? This will be empty if expat was not available. LIBEXPAT = @LIBEXPAT@ +# Where is lzma? This will be empty if lzma was not available. +LIBLZMA = @LIBLZMA@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ # LIBIBERTY appears twice on purpose. CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ - $(LIBEXPAT) \ + $(LIBEXPAT) $(LIBLZMA) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inline-frame.c \ interps.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ - language.c linespec.c \ + language.c linespec.c minidebug.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ filesystem.o \ inf-child.o \ interps.o \ + minidebug.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ diff --git a/gdb/NEWS b/gdb/NEWS index 5e3f54d..3b09e5f 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -100,6 +100,11 @@ show print type typedefs ** New optional parameter COUNT added to the "-data-write-memory-bytes" command, to allow pattern filling of memory areas. +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. + You must have the LZMA library available when configuring GDB for this + feature to be enabled. For more information, see: + http://fedoraproject.org/wiki/Features/MiniDebugInfo + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/configure.ac b/gdb/configure.ac index 030fb06..9791143 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2053,6 +2053,27 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 80148f7..afe3845 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* MiniDebugInfo:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -16790,6 +16791,55 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node MiniDebugInfo +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This feature is called +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and +is used to supply extra symbols for backtraces. + +The intent of this section is to provide extra minimal debugging +information for use in simple backtraces. It is not intended to be a +replacement for full separate debugging information (@pxref{Separate +Debug Files}). The example below shows the intended use; however, +@value{GDBN} does not currently put restrictions on what sort of +debugging information might be included in the section. + +@value{GDBN} has support for this extension. If the section exists, +then it is used provided that no other source of debugging information +can be found, and that @value{GDBN} was configured with LZMA support. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} diff --git a/gdb/minidebug.c b/gdb/minidebug.c new file mode 100644 index 0000000..d74432a --- /dev/null +++ b/gdb/minidebug.c @@ -0,0 +1,288 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include <lzma.h> + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + if (objfile->obfd == NULL) + return NULL; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + warning (_("Cannot parse .gnu_debugdata section; not a BFD object")); + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/gdb/symfile.c b/gdb/symfile.c index 55af541..6a2fc89 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + if (!objfile_has_partial_symbols (objfile)) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -2601,14 +2619,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bb75c18..223f874 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c new file mode 100644 index 0000000..b8b7e8a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 <signal.h> + +static int +debugdata_function (void) +{ + return raise (SIGSEGV) + 1; +} + +int +main (void) +{ + return debugdata_function () + 1; +} diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp new file mode 100644 index 0000000..f876309 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -0,0 +1,157 @@ +# Copyright 2012 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/>. + +standard_testfile + +if [build_executable ${testfile}.exp $testfile] { + return -1 +} + +# A wrapper for 'remote_exec host' that passes or fails a test. +# Returns 0 if all went well, nonzero on failure. +# TEST is the name of the test, other arguments are as for +# remote_exec. +proc run {test program args} { + verbose "cmdline is remote_exec host $program $args" + # remote_exec doesn't work properly if the output is set but the + # input is the empty string -- so replace an empty input with + # /dev/null. + if {[llength $args] > 1 && [lindex $args 1] == ""} { + set args [lreplace $args 1 1 "/dev/null"] + } + set result [eval remote_exec host [list $program] $args] + verbose "result is $result" + lassign $result status output + if {$status == 0} { + pass $test + return 0 + } else { + fail $test + return -1 + } +} + +set pipeline_counter 0 + +# Run a pipeline of processes through 'run'. +# TEST is the base name of the test, it is modified and passed to 'run'. +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. +# It is passed to 'run'. However, before being passed, if input and output +# files are not specified in the list, then this proc provides them. +# Each program in the pipeline takes its input from the previous +# program's output. +proc pipeline {test args} { + global pipeline_counter + + set input_file {} + foreach arglist $args { + verbose "raw args are $arglist" + lassign $arglist program arguments input output + + if {$input == ""} { + set input $input_file + } + if {$output == ""} { + set output [standard_output_file pipe.[pid].$pipeline_counter] + incr pipeline_counter + } + verbose "cooked args are [list $program $arguments $input $output]" + + if {[run "$test - invoke $program" $program $arguments \ + $input $output]} { + return -1 + } + + set input_file $output + } + return 0 +} + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. +remote_file host delete ${binfile}.dynsyms +if {[pipeline "nm -D" \ + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ + [list awk "\\{print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.dynsyms"]]} { + return -1 +} + +# Extract all the text (i.e. function) symbols from the debuginfo. +remote_file host delete ${binfile}.funcsyms +if {[pipeline "nm" \ + [list [transform nm] "${binfile} --format=posix --defined-only"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.funcsyms"]]} { + return -1 +} + +# Keep all the function symbols not already in the dynamic symbol +# table. +remote_file host delete ${binfile}.keep_symbols +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ + "${binfile}.keep_symbols"]} { + return -1 +} + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +remote_file host delete ${binfile}.mini_debuginfo +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { + return -1 +} + +# GDB specific - we do not have split executable in advance. +remote_file host delete ${binfile}.strip +if {[run "strip" [transform strip] \ + "--strip-all -o ${binfile}.strip ${binfile}"]} { + return -1 +} + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +remote_file host delete ${binfile}.mini_debuginfo.xz +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { + return -1 +} +remote_file host delete ${binfile}.test +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { + return -1 +} + +clean_restart "$testfile.strip" + +gdb_test "p debugdata_function" \ + {No symbol table is loaded\. Use the "file" command\.} \ + "no symtab" + +clean_restart "$testfile.test" + +if {$gdb_file_cmd_debug_info == "lzma"} { + unsupported "LZMA support not available in this gdb" +} else { + gdb_test "p debugdata_function" \ + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ + "have symtab" +} + +# Be sure to test the 'close' method on the MiniDebugInfo BFD. +if {[gdb_unload]} { + fail "unload MiniDebugInfo" +} else { + pass "unload MiniDebugInfo" +} + +gdb_exit diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 16e8b54..781ccc8 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -128,6 +128,7 @@ proc gdb_version { } { # # gdb_unload -- unload a file if one is loaded +# Return 0 on success, -1 on error. # proc gdb_unload {} { @@ -152,6 +153,7 @@ proc gdb_unload {} { return -1 } } + return 0 } # Many of the tests depend on setting breakpoints at various places and @@ -1278,6 +1280,8 @@ proc default_gdb_exit {} { # # debug file was loaded successfully and has debug information # nodebug file was loaded successfully and has no debug information +# lzma file was loaded, .gnu_debugdata found, but no LZMA support +# compiled in # fail file was not loaded # # I tried returning this information as part of the return value, @@ -1325,6 +1329,11 @@ proc gdb_file_cmd { arg } { send_gdb "file $arg\n" gdb_expect 120 { + -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" { + verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available" + set gdb_file_cmd_debug_info "lzma" + return 0 + } -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into $GDB with no debugging symbols" set gdb_file_cmd_debug_info "nodebug" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-26 19:21 ` Tom Tromey @ 2012-11-26 22:24 ` Andrew Pinski 2012-11-27 2:23 ` Tom Tromey 2012-11-29 19:19 ` Ulrich Weigand 2012-12-11 16:42 ` Yufeng Zhang 2 siblings, 1 reply; 42+ messages in thread From: Andrew Pinski @ 2012-11-26 22:24 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, Doug Evans, gdb-patches On Mon, Nov 26, 2012 at 11:20 AM, Tom Tromey <tromey@redhat.com> wrote: >>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: > > Pedro> Do we spell out the same requirement for separate debug files? I > Pedro> still fail to see why we don't just describe this as what it is, > Pedro> not less nor more: exactly the same as separate debug file, but > Pedro> instead of being found as a separate file in the file system, > Pedro> it's tucked along inside the main binary. > > Doug said off-list that he would be ok with what I was planning to put > in. > > So, here is the final patch which I am committing. I removed the BFD > flavour check and the corresponding paragraph from the manual. > > Built and regtested on x86-64 Fedora 16. > > Tom > > 2012-11-26 Alexander Larsson <alexl@redhat.com> > Jan Kratochvil <jan.kratochvil@redhat.com> > Tom Tromey <tromey@redhat.com> > > * NEWS: Mention mini debuginfo feature. > * minidebug.c: New file. > * configure.ac: Check for lzma. > * configure, config.in: Rebuild. > * Makefile.in (LIBLZMA): New variable. > (CLIBS): Include LIBLZMA. > (SFILES): Mention minidebug.c. > (COMMON_OBS): Mention minidebug.o. > * symfile.c (read_symbols): New function. > (syms_from_objfile, reread_symbols): Call it. > * symfile.h (find_separate_debug_file_in_section): Declare. > > 2012-11-26 Tom Tromey <tromey@redhat.com> > > * gdb.texinfo (MiniDebugInfo): New node. > (GDB Files): Update. > > 2012-11-26 Jan Kratochvil <jan.kratochvil@redhat.com> > Tom Tromey <tromey@redhat.com> > > * gdb.base/gnu-debugdata.exp: New file. > * gdb.base/gnu-debugdata.c: New file. > * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. > (gdb_unload): Return 0 on success. Looks like minidebug.c was not committed. Thanks, Andrew Pinski > > diff --git a/gdb/Makefile.in b/gdb/Makefile.in > index e9aeb0c..3dd7b85 100644 > --- a/gdb/Makefile.in > +++ b/gdb/Makefile.in > @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ > # Where is expat? This will be empty if expat was not available. > LIBEXPAT = @LIBEXPAT@ > > +# Where is lzma? This will be empty if lzma was not available. > +LIBLZMA = @LIBLZMA@ > + > WARN_CFLAGS = @WARN_CFLAGS@ > WERROR_CFLAGS = @WERROR_CFLAGS@ > GDB_WARN_CFLAGS = $(WARN_CFLAGS) > @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ > # LIBIBERTY appears twice on purpose. > CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ > $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ > - $(LIBEXPAT) \ > + $(LIBEXPAT) $(LIBLZMA) \ > $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) > CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ > $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) > @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ > inline-frame.c \ > interps.c \ > jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ > - language.c linespec.c \ > + language.c linespec.c minidebug.c \ > m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ > macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ > mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ > @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ > filesystem.o \ > inf-child.o \ > interps.o \ > + minidebug.o \ > main.o \ > macrotab.o macrocmd.o macroexp.o macroscope.o \ > mi-common.o \ > diff --git a/gdb/NEWS b/gdb/NEWS > index 5e3f54d..3b09e5f 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -100,6 +100,11 @@ show print type typedefs > ** New optional parameter COUNT added to the "-data-write-memory-bytes" > command, to allow pattern filling of memory areas. > > +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. > + You must have the LZMA library available when configuring GDB for this > + feature to be enabled. For more information, see: > + http://fedoraproject.org/wiki/Features/MiniDebugInfo > + > *** Changes in GDB 7.5 > > * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> > diff --git a/gdb/configure.ac b/gdb/configure.ac > index 030fb06..9791143 100644 > --- a/gdb/configure.ac > +++ b/gdb/configure.ac > @@ -2053,6 +2053,27 @@ LIBS=$OLD_LIBS > # Add any host-specific objects to GDB. > CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" > > +# If building on ELF, look for lzma support for embedded compressed debug info. > +if test $gdb_cv_var_elf = yes; then > + AC_ARG_WITH(lzma, > + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), > + [], [with_lzma=auto]) > + AC_MSG_CHECKING([whether to use lzma]) > + AC_MSG_RESULT([$with_lzma]) > + > + if test "${with_lzma}" != no; then > + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], > + [lzma_index_iter iter; > + lzma_index_iter_init (&iter, 0); > + lzma_mf_is_supported (LZMA_MF_HC3);]) > + if test "$HAVE_LIBLZMA" != yes; then > + if test "$with_lzma" = yes; then > + AC_MSG_ERROR([missing liblzma for --with-lzma]) > + fi > + fi > + fi > +fi > + > LIBGUI="../libgui/src/libgui.a" > GUI_CFLAGS_X="-I${srcdir}/../libgui/src" > AC_SUBST(LIBGUI) > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 80148f7..afe3845 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell > @menu > * Files:: Commands to specify files > * Separate Debug Files:: Debugging information in separate files > +* MiniDebugInfo:: Debugging information in a special section > * Index Files:: Index files speed up GDB > * Symbol Errors:: Errors reading symbol files > * Data Files:: GDB data files > @@ -16790,6 +16791,55 @@ gnu_debuglink_crc32 (unsigned long crc, > @noindent > This computation does not apply to the ``build ID'' method. > > +@node MiniDebugInfo > +@section Debugging information in a special section > +@cindex separate debug sections > +@cindex @samp{.gnu_debugdata} section > + > +Some systems ship pre-built executables and libraries that have a > +special @samp{.gnu_debugdata} section. This feature is called > +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and > +is used to supply extra symbols for backtraces. > + > +The intent of this section is to provide extra minimal debugging > +information for use in simple backtraces. It is not intended to be a > +replacement for full separate debugging information (@pxref{Separate > +Debug Files}). The example below shows the intended use; however, > +@value{GDBN} does not currently put restrictions on what sort of > +debugging information might be included in the section. > + > +@value{GDBN} has support for this extension. If the section exists, > +then it is used provided that no other source of debugging information > +can be found, and that @value{GDBN} was configured with LZMA support. > + > +This section can be easily created using @command{objcopy} and other > +standard utilities: > + > +@smallexample > +# Extract the dynamic symbols from the main binary, there is no need > +# to also have these in the normal symbol table > +nm -D @var{binary} --format=posix --defined-only \ > + | awk '@{ print $1 @}' | sort > dynsyms > + > +# Extract all the text (i.e. function) symbols from the debuginfo . > +nm @var{binary} --format=posix --defined-only \ > + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ > + | sort > funcsyms > + > +# Keep all the function symbols not already in the dynamic symbol > +# table. > +comm -13 dynsyms funcsyms > keep_symbols > + > +# Copy the full debuginfo, keeping only a minimal set of symbols and > +# removing some unnecessary sections. > +objcopy -S --remove-section .gdb_index --remove-section .comment \ > + --keep-symbols=keep_symbols @var{binary} mini_debuginfo > + > +# Inject the compressed data into the .gnu_debugdata section of the > +# original binary. > +xz mini_debuginfo > +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} > +@end smallexample > > @node Index Files > @section Index Files Speed Up @value{GDBN} > diff --git a/gdb/minidebug.c b/gdb/minidebug.c > new file mode 100644 > index 0000000..d74432a > --- /dev/null > +++ b/gdb/minidebug.c > @@ -0,0 +1,288 @@ > +/* Read MiniDebugInfo data from an objfile. > + > + Copyright (C) 2012 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see <http://www.gnu.org/licenses/>. */ > + > +#include "defs.h" > +#include "gdb_bfd.h" > +#include "gdb_string.h" > +#include "symfile.h" > +#include "objfiles.h" > +#include "gdbcore.h" > + > +#ifdef HAVE_LIBLZMA > + > +#include <lzma.h> > + > +/* Allocator function for LZMA. */ > + > +static void * > +alloc_lzma (void *opaque, size_t nmemb, size_t size) > +{ > + return xmalloc (nmemb * size); > +} > + > +/* Free function for LZMA. */ > + > +static void > +free_lzma (void *opaque, void *ptr) > +{ > + xfree (ptr); > +} > + > +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' > + cannot be const due to the lzma library function prototypes. */ > + > +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; > + > +/* Custom bfd_openr_iovec implementation to read compressed data from > + a section. This keeps only the last decompressed block in memory > + to allow larger data without using to much memory. */ > + > +struct lzma_stream > +{ > + /* Section of input BFD from which we are decoding data. */ > + asection *section; > + > + /* lzma library decompression state. */ > + lzma_index *index; > + > + /* Currently decoded block. */ > + bfd_size_type data_start; > + bfd_size_type data_end; > + gdb_byte *data; > +}; > + > +/* bfd_openr_iovec OPEN_P implementation for > + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' > + of the section to decompress. > + > + Return 'struct lzma_stream *' must be freed by caller by xfree, together > + with its INDEX lzma data. */ > + > +static void * > +lzma_open (struct bfd *nbfd, void *open_closure) > +{ > + asection *section = open_closure; > + bfd_size_type size, offset; > + lzma_stream_flags options; > + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; > + gdb_byte *indexdata; > + lzma_index *index; > + int ret; > + uint64_t memlimit = UINT64_MAX; > + struct lzma_stream *lstream; > + size_t pos; > + > + size = bfd_get_section_size (section); > + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; > + if (size < LZMA_STREAM_HEADER_SIZE > + || bfd_seek (section->owner, offset, SEEK_SET) != 0 > + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) > + != LZMA_STREAM_HEADER_SIZE > + || lzma_stream_footer_decode (&options, footer) != LZMA_OK > + || offset < options.backward_size) > + { > + bfd_set_error (bfd_error_wrong_format); > + return NULL; > + } > + > + offset -= options.backward_size; > + indexdata = xmalloc (options.backward_size); > + index = NULL; > + pos = 0; > + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 > + || bfd_bread (indexdata, options.backward_size, section->owner) > + != options.backward_size > + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, > + indexdata, &pos, options.backward_size) > + != LZMA_OK > + || lzma_index_size (index) != options.backward_size) > + { > + xfree (indexdata); > + bfd_set_error (bfd_error_wrong_format); > + return NULL; > + } > + xfree (indexdata); > + > + lstream = xzalloc (sizeof (struct lzma_stream)); > + lstream->section = section; > + lstream->index = index; > + > + return lstream; > +} > + > +/* bfd_openr_iovec PREAD_P implementation for > + find_separate_debug_file_in_section. Passed STREAM > + is 'struct lzma_stream *'. */ > + > +static file_ptr > +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, > + file_ptr offset) > +{ > + struct lzma_stream *lstream = stream; > + bfd_size_type chunk_size; > + lzma_index_iter iter; > + gdb_byte *compressed, *uncompressed; > + file_ptr block_offset; > + lzma_filter filters[LZMA_FILTERS_MAX + 1]; > + lzma_block block; > + size_t compressed_pos, uncompressed_pos; > + file_ptr res; > + > + res = 0; > + while (nbytes > 0) > + { > + if (lstream->data == NULL > + || lstream->data_start > offset || offset >= lstream->data_end) > + { > + asection *section = lstream->section; > + > + lzma_index_iter_init (&iter, lstream->index); > + if (lzma_index_iter_locate (&iter, offset)) > + break; > + > + compressed = xmalloc (iter.block.total_size); > + block_offset = section->filepos + iter.block.compressed_file_offset; > + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 > + || bfd_bread (compressed, iter.block.total_size, section->owner) > + != iter.block.total_size) > + { > + xfree (compressed); > + break; > + } > + > + uncompressed = xmalloc (iter.block.uncompressed_size); > + > + memset (&block, 0, sizeof (block)); > + block.filters = filters; > + block.header_size = lzma_block_header_size_decode (compressed[0]); > + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) > + != LZMA_OK) > + { > + xfree (compressed); > + xfree (uncompressed); > + break; > + } > + > + compressed_pos = block.header_size; > + uncompressed_pos = 0; > + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, > + compressed, &compressed_pos, > + iter.block.total_size, > + uncompressed, &uncompressed_pos, > + iter.block.uncompressed_size) > + != LZMA_OK) > + { > + xfree (compressed); > + xfree (uncompressed); > + break; > + } > + > + xfree (compressed); > + > + xfree (lstream->data); > + lstream->data = uncompressed; > + lstream->data_start = iter.block.uncompressed_file_offset; > + lstream->data_end = (iter.block.uncompressed_file_offset > + + iter.block.uncompressed_size); > + } > + > + chunk_size = min (nbytes, lstream->data_end - offset); > + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); > + buf = (gdb_byte *) buf + chunk_size; > + offset += chunk_size; > + nbytes -= chunk_size; > + res += chunk_size; > + } > + > + return res; > +} > + > +/* bfd_openr_iovec CLOSE_P implementation for > + find_separate_debug_file_in_section. Passed STREAM > + is 'struct lzma_stream *'. */ > + > +static int > +lzma_close (struct bfd *nbfd, > + void *stream) > +{ > + struct lzma_stream *lstream = stream; > + > + lzma_index_end (lstream->index, &gdb_lzma_allocator); > + xfree (lstream->data); > + xfree (lstream); > + return 0; > +} > + > +/* bfd_openr_iovec STAT_P implementation for > + find_separate_debug_file_in_section. Passed STREAM > + is 'struct lzma_stream *'. */ > + > +static int > +lzma_stat (struct bfd *abfd, > + void *stream, > + struct stat *sb) > +{ > + struct lzma_stream *lstream = stream; > + > + sb->st_size = lzma_index_uncompressed_size (lstream->index); > + return 0; > +} > + > +#endif /* HAVE_LIBLZMA */ > + > +/* This looks for a xz compressed separate debug info object file embedded > + in a section called .gnu_debugdata. See > + http://fedoraproject.org/wiki/Features/MiniDebugInfo > + or the "Separate Debug Sections" of the manual for details. > + If we find one we create a iovec based bfd that decompresses the > + object data on demand. If we don't find one, return NULL. */ > + > +bfd * > +find_separate_debug_file_in_section (struct objfile *objfile) > +{ > + asection *section; > + bfd *abfd; > + > + if (objfile->obfd == NULL) > + return NULL; > + > + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); > + if (section == NULL) > + return NULL; > + > +#ifdef HAVE_LIBLZMA > + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, > + lzma_pread, lzma_close, lzma_stat); > + if (abfd == NULL) > + return NULL; > + > + if (!bfd_check_format (abfd, bfd_object)) > + { > + warning (_("Cannot parse .gnu_debugdata section; not a BFD object")); > + gdb_bfd_unref (abfd); > + return NULL; > + } > +#else > + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " > + "disabled at compile time")); > + abfd = NULL; > +#endif /* !HAVE_LIBLZMA */ > + > + return abfd; > +} > diff --git a/gdb/symfile.c b/gdb/symfile.c > index 55af541..6a2fc89 100644 > --- a/gdb/symfile.c > +++ b/gdb/symfile.c > @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) > return data; > } > > +/* This is a convenience function to call sym_read for OBJFILE and > + possibly force the partial symbols to be read. */ > + > +static void > +read_symbols (struct objfile *objfile, int add_flags) > +{ > + (*objfile->sf->sym_read) (objfile, add_flags); > + if (!objfile_has_partial_symbols (objfile)) > + { > + bfd *abfd = find_separate_debug_file_in_section (objfile); > + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); > + > + if (abfd != NULL) > + symbol_file_add_separate (abfd, add_flags, objfile); > + > + do_cleanups (cleanup); > + } > + if ((add_flags & SYMFILE_NO_READ) == 0) > + require_partial_symbols (objfile, 0); > +} > + > /* Process a symbol file, as either the main file or as a dynamically > loaded file. > > @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, > init_objfile_sect_indices (objfile); > } > > - (*objfile->sf->sym_read) (objfile, add_flags); > - > - if ((add_flags & SYMFILE_NO_READ) == 0) > - require_partial_symbols (objfile, 0); > + read_symbols (objfile, add_flags); > > /* Discard cleanups as symbol reading was successful. */ > > @@ -2601,14 +2619,9 @@ reread_symbols (void) > > (*objfile->sf->sym_init) (objfile); > clear_complaints (&symfile_complaints, 1, 1); > - /* Do not set flags as this is safe and we don't want to be > - verbose. */ > - (*objfile->sf->sym_read) (objfile, 0); > - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) > - { > - objfile->flags &= ~OBJF_PSYMTABS_READ; > - require_partial_symbols (objfile, 0); > - } > + > + objfile->flags &= ~OBJF_PSYMTABS_READ; > + read_symbols (objfile, 0); > > if (!objfile_has_symbols (objfile)) > { > diff --git a/gdb/symfile.h b/gdb/symfile.h > index bb75c18..223f874 100644 > --- a/gdb/symfile.h > +++ b/gdb/symfile.h > @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, > const struct ecoff_debug_swap *, > asection *); > > +/* From minidebug.c. */ > + > +extern bfd *find_separate_debug_file_in_section (struct objfile *); > + > #endif /* !defined(SYMFILE_H) */ > diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c > new file mode 100644 > index 0000000..b8b7e8a > --- /dev/null > +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c > @@ -0,0 +1,30 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2012 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 <signal.h> > + > +static int > +debugdata_function (void) > +{ > + return raise (SIGSEGV) + 1; > +} > + > +int > +main (void) > +{ > + return debugdata_function () + 1; > +} > diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp > new file mode 100644 > index 0000000..f876309 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp > @@ -0,0 +1,157 @@ > +# Copyright 2012 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/>. > + > +standard_testfile > + > +if [build_executable ${testfile}.exp $testfile] { > + return -1 > +} > + > +# A wrapper for 'remote_exec host' that passes or fails a test. > +# Returns 0 if all went well, nonzero on failure. > +# TEST is the name of the test, other arguments are as for > +# remote_exec. > +proc run {test program args} { > + verbose "cmdline is remote_exec host $program $args" > + # remote_exec doesn't work properly if the output is set but the > + # input is the empty string -- so replace an empty input with > + # /dev/null. > + if {[llength $args] > 1 && [lindex $args 1] == ""} { > + set args [lreplace $args 1 1 "/dev/null"] > + } > + set result [eval remote_exec host [list $program] $args] > + verbose "result is $result" > + lassign $result status output > + if {$status == 0} { > + pass $test > + return 0 > + } else { > + fail $test > + return -1 > + } > +} > + > +set pipeline_counter 0 > + > +# Run a pipeline of processes through 'run'. > +# TEST is the base name of the test, it is modified and passed to 'run'. > +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. > +# It is passed to 'run'. However, before being passed, if input and output > +# files are not specified in the list, then this proc provides them. > +# Each program in the pipeline takes its input from the previous > +# program's output. > +proc pipeline {test args} { > + global pipeline_counter > + > + set input_file {} > + foreach arglist $args { > + verbose "raw args are $arglist" > + lassign $arglist program arguments input output > + > + if {$input == ""} { > + set input $input_file > + } > + if {$output == ""} { > + set output [standard_output_file pipe.[pid].$pipeline_counter] > + incr pipeline_counter > + } > + verbose "cooked args are [list $program $arguments $input $output]" > + > + if {[run "$test - invoke $program" $program $arguments \ > + $input $output]} { > + return -1 > + } > + > + set input_file $output > + } > + return 0 > +} > + > +# Extract the dynamic symbols from the main binary, there is no need > +# to also have these in the normal symbol table. > +remote_file host delete ${binfile}.dynsyms > +if {[pipeline "nm -D" \ > + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ > + [list awk "\\{print\\ \\\$1\\}"] \ > + [list sort "" "" "${binfile}.dynsyms"]]} { > + return -1 > +} > + > +# Extract all the text (i.e. function) symbols from the debuginfo. > +remote_file host delete ${binfile}.funcsyms > +if {[pipeline "nm" \ > + [list [transform nm] "${binfile} --format=posix --defined-only"] \ > + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ > + [list sort "" "" "${binfile}.funcsyms"]]} { > + return -1 > +} > + > +# Keep all the function symbols not already in the dynamic symbol > +# table. > +remote_file host delete ${binfile}.keep_symbols > +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ > + "${binfile}.keep_symbols"]} { > + return -1 > +} > + > +# Copy the full debuginfo, keeping only a minimal set of symbols and > +# removing some unnecessary sections. > +remote_file host delete ${binfile}.mini_debuginfo > +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { > + return -1 > +} > + > +# GDB specific - we do not have split executable in advance. > +remote_file host delete ${binfile}.strip > +if {[run "strip" [transform strip] \ > + "--strip-all -o ${binfile}.strip ${binfile}"]} { > + return -1 > +} > + > +# Inject the compressed data into the .gnu_debugdata section of the > +# original binary. > +remote_file host delete ${binfile}.mini_debuginfo.xz > +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { > + return -1 > +} > +remote_file host delete ${binfile}.test > +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { > + return -1 > +} > + > +clean_restart "$testfile.strip" > + > +gdb_test "p debugdata_function" \ > + {No symbol table is loaded\. Use the "file" command\.} \ > + "no symtab" > + > +clean_restart "$testfile.test" > + > +if {$gdb_file_cmd_debug_info == "lzma"} { > + unsupported "LZMA support not available in this gdb" > +} else { > + gdb_test "p debugdata_function" \ > + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ > + "have symtab" > +} > + > +# Be sure to test the 'close' method on the MiniDebugInfo BFD. > +if {[gdb_unload]} { > + fail "unload MiniDebugInfo" > +} else { > + pass "unload MiniDebugInfo" > +} > + > +gdb_exit > diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp > index 16e8b54..781ccc8 100644 > --- a/gdb/testsuite/lib/gdb.exp > +++ b/gdb/testsuite/lib/gdb.exp > @@ -128,6 +128,7 @@ proc gdb_version { } { > > # > # gdb_unload -- unload a file if one is loaded > +# Return 0 on success, -1 on error. > # > > proc gdb_unload {} { > @@ -152,6 +153,7 @@ proc gdb_unload {} { > return -1 > } > } > + return 0 > } > > # Many of the tests depend on setting breakpoints at various places and > @@ -1278,6 +1280,8 @@ proc default_gdb_exit {} { > # > # debug file was loaded successfully and has debug information > # nodebug file was loaded successfully and has no debug information > +# lzma file was loaded, .gnu_debugdata found, but no LZMA support > +# compiled in > # fail file was not loaded > # > # I tried returning this information as part of the return value, > @@ -1325,6 +1329,11 @@ proc gdb_file_cmd { arg } { > > send_gdb "file $arg\n" > gdb_expect 120 { > + -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" { > + verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available" > + set gdb_file_cmd_debug_info "lzma" > + return 0 > + } > -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { > verbose "\t\tLoaded $arg into $GDB with no debugging symbols" > set gdb_file_cmd_debug_info "nodebug" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-26 22:24 ` Andrew Pinski @ 2012-11-27 2:23 ` Tom Tromey 0 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-27 2:23 UTC (permalink / raw) To: Andrew Pinski; +Cc: Pedro Alves, Doug Evans, gdb-patches >>>>> "Andrew" == Andrew Pinski <pinskia@gmail.com> writes: Andrew> Looks like minidebug.c was not committed. The famous missing "cvs add". I fixed it. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-26 19:21 ` Tom Tromey 2012-11-26 22:24 ` Andrew Pinski @ 2012-11-29 19:19 ` Ulrich Weigand 2012-11-29 19:23 ` Tom Tromey 2012-12-11 16:42 ` Yufeng Zhang 2 siblings, 1 reply; 42+ messages in thread From: Ulrich Weigand @ 2012-11-29 19:19 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, Doug Evans, gdb-patches Tom Tromey wrote: > +# Run a pipeline of processes through 'run'. > +# TEST is the base name of the test, it is modified and passed to 'run'. > +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. > +# It is passed to 'run'. However, before being passed, if input and output > +# files are not specified in the list, then this proc provides them. > +# Each program in the pipeline takes its input from the previous > +# program's output. > +proc pipeline {test args} { > + global pipeline_counter > + > + set input_file {} > + foreach arglist $args { > + verbose "raw args are $arglist" > + lassign $arglist program arguments input output > + > + if {$input == ""} { > + set input $input_file > + } > + if {$output == ""} { > + set output [standard_output_file pipe.[pid].$pipeline_counter] > + incr pipeline_counter > + } > + verbose "cooked args are [list $program $arguments $input $output]" > + > + if {[run "$test - invoke $program" $program $arguments \ > + $input $output]} { > + return -1 > + } > + > + set input_file $output > + } > + return 0 > +} > + > +# Extract the dynamic symbols from the main binary, there is no need > +# to also have these in the normal symbol table. > +remote_file host delete ${binfile}.dynsyms > +if {[pipeline "nm -D" \ > + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ > + [list awk "\\{print\\ \\\$1\\}"] \ > + [list sort "" "" "${binfile}.dynsyms"]]} { > + return -1 > +} This causes DejaGnu to abort for me with: ERROR: (DejaGnu) proc "lassign {nm {-D /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata --format=posix --defined-only}} program arguments input output" does not exist. I'm not really familiar enough with DejaGnu/Tcl to quite understand what's going on here ... Any thoughts? Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-29 19:19 ` Ulrich Weigand @ 2012-11-29 19:23 ` Tom Tromey 2012-11-29 19:33 ` Ulrich Weigand 0 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-29 19:23 UTC (permalink / raw) To: Ulrich Weigand; +Cc: Pedro Alves, Doug Evans, gdb-patches >>>>> "Ulrich" == Ulrich Weigand <uweigand@de.ibm.com> writes: Ulrich> ERROR: (DejaGnu) proc "lassign {nm {-D Ulrich> /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata Ulrich> --format=posix --defined-only}} program arguments input output" does Ulrich> not exist. Ulrich> I'm not really familiar enough with DejaGnu/Tcl to quite understand Ulrich> what's going on here ... Any thoughts? I think lassign was added in Tcl 8.5. You must be running an older version. Can you try the appended? Tom diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp index f876309..1429a39 100644 --- a/gdb/testsuite/gdb.base/gnu-debugdata.exp +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -33,7 +33,8 @@ proc run {test program args} { } set result [eval remote_exec host [list $program] $args] verbose "result is $result" - lassign $result status output + set status [lindex $result 0] + set output [lindex $result 1] if {$status == 0} { pass $test return 0 @@ -58,7 +59,11 @@ proc pipeline {test args} { set input_file {} foreach arglist $args { verbose "raw args are $arglist" - lassign $arglist program arguments input output + + set program [lindex $arglist 0] + set arguments [lindex $arglist 1] + set input [lindex $arglist 2] + set output [lindex $arglist 3] if {$input == ""} { set input $input_file ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-29 19:23 ` Tom Tromey @ 2012-11-29 19:33 ` Ulrich Weigand 2012-11-29 20:51 ` Tom Tromey 0 siblings, 1 reply; 42+ messages in thread From: Ulrich Weigand @ 2012-11-29 19:33 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, Doug Evans, gdb-patches Tom Tromey wrote: > I think lassign was added in Tcl 8.5. > You must be running an older version. > > Can you try the appended? Yes, that works for me! Thanks for the quick fix! However, now that the test case actually runs, it fails with: FAIL: gdb.base/gnu-debugdata.exp: objcopy 1 Apparently this happens because: objcopy -S --remove-section .gdb_index --remove-section .comment --keep-symbols=/home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata.keep_symbols /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata.mini_debuginfo returns a non-zero exit code since the original binary has no .gdb_index section (probably because the system compiler is old) ... Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-29 19:33 ` Ulrich Weigand @ 2012-11-29 20:51 ` Tom Tromey 2012-11-30 14:05 ` Ulrich Weigand 0 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-29 20:51 UTC (permalink / raw) To: Ulrich Weigand; +Cc: Pedro Alves, Doug Evans, gdb-patches >>>>> "Ulrich" == Ulrich Weigand <uweigand@de.ibm.com> writes: Tom> Can you try the appended? Ulrich> Yes, that works for me! Thanks for the quick fix! I'm going to check it in with this ChangeLog: 2012-11-29 Tom Tromey <tromey@redhat.com> * gdb.base/gnu-debugdata.exp (run, pipeline): Don't use lassign. Ulrich> FAIL: gdb.base/gnu-debugdata.exp: objcopy 1 Ulrich> Apparently this happens because: Ulrich> objcopy -S --remove-section .gdb_index --remove-section .comment Ulrich> --keep-symbols=/home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata.keep_symbols Ulrich> /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata Ulrich> /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata.mini_debuginfo Ulrich> returns a non-zero exit code since the original binary has no .gdb_index Ulrich> section (probably because the system compiler is old) ... My system doesn't make a .gdb_index by default. So it must be something else. Does your objcopy work if you omit that --remove-section? I wonder if it is an objcopy difference. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-29 20:51 ` Tom Tromey @ 2012-11-30 14:05 ` Ulrich Weigand 2012-11-30 20:59 ` Tom Tromey 0 siblings, 1 reply; 42+ messages in thread From: Ulrich Weigand @ 2012-11-30 14:05 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, Doug Evans, gdb-patches Tom Tromey wrote: > >>>>> "Ulrich" == Ulrich Weigand <uweigand@de.ibm.com> writes: > Ulrich> Yes, that works for me! Thanks for the quick fix! > > I'm going to check it in with this ChangeLog: Thanks! > Ulrich> FAIL: gdb.base/gnu-debugdata.exp: objcopy 1 > Ulrich> Apparently this happens because: > Ulrich> objcopy -S --remove-section .gdb_index --remove-section .comment > Ulrich> --keep-symbols=/home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata.keep_symbols > Ulrich> /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata > Ulrich> /home/uweigand/fsf/gdb-head-build/gdb/testsuite/gdb.base/gnu-debugdata.mini_debuginfo > > Ulrich> returns a non-zero exit code since the original binary has no .gdb_index > Ulrich> section (probably because the system compiler is old) ... > > My system doesn't make a .gdb_index by default. > So it must be something else. Right, it turns out the problem isn't the --remove-section; the problem rather seems to be that the file passed for --keep-symbols is empty. This in turn is because of the filter for "T" type symbols: if {[pipeline "nm" \ [list [transform nm] "${binfile} --format=posix --defined-only"] \ [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ [list sort "" "" "${binfile}.funcsyms"]]} { The problem on PowerPC64 is that the main function entry points refer to function descriptors in the data section, and are thus labeled "D" instead of "T": _DYNAMIC d 0000000010010948 _IO_stdin_used R 0000000010000820 0000000000000004 __CTOR_END__ d 0000000010010908 __CTOR_LIST__ d 0000000010010900 __DTOR_END__ D 0000000010010918 __DTOR_LIST__ d 0000000010010910 __FRAME_END__ r 00000000100008f8 __JCR_END__ d 0000000010010920 __JCR_LIST__ d 0000000010010920 __bss_start A 0000000010010be0 __data_start D 0000000010010ac8 __do_global_ctors_aux d 0000000010010b68 __do_global_dtors_aux d 0000000010010b08 __dso_handle R 0000000010000828 __fini_array_end d 00000000100108fc __fini_array_start d 00000000100108fc __init_array_end d 00000000100108fc __init_array_start d 00000000100108fc __libc_csu_fini D 0000000010010b48 0000000000000010 __libc_csu_init D 0000000010010b58 00000000000000d0 __preinit_array_end d 00000000100108fc __preinit_array_start d 00000000100108fc _edata A 0000000010010be0 _end A 0000000010010c50 _fini D 0000000010010af8 _init D 0000000010010ae8 _start D 0000000010010ac8 000000000000003c call_gmon_start d 0000000010010ad8 completed.6441 b 0000000010010c48 0000000000000001 data_start W 0000000010010ac8 debugdata_function d 0000000010010b28 0000000000000054 dtor_idx.6443 b 0000000010010c40 0000000000000008 frame_dummy d 0000000010010b18 main D 0000000010010b38 000000000000004c If I change the above filter to also accept "D", the test case goes further. (It still ends up UNSUPPORTED, since it looks like I don't have LZMA on the system ...). I'm not sure why the filter for "T" is done; would it change something critical to the test if "D" were added? Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-30 14:05 ` Ulrich Weigand @ 2012-11-30 20:59 ` Tom Tromey 2012-12-05 17:09 ` Ulrich Weigand 0 siblings, 1 reply; 42+ messages in thread From: Tom Tromey @ 2012-11-30 20:59 UTC (permalink / raw) To: Ulrich Weigand; +Cc: Pedro Alves, Doug Evans, gdb-patches Ulrich> If I change the above filter to also accept "D", the test case Ulrich> goes further. (It still ends up UNSUPPORTED, since it looks Ulrich> like I don't have LZMA on the system ...). I'm not sure why the Ulrich> filter for "T" is done; would it change something critical to Ulrich> the test if "D" were added? I think it would be fine. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-30 20:59 ` Tom Tromey @ 2012-12-05 17:09 ` Ulrich Weigand 0 siblings, 0 replies; 42+ messages in thread From: Ulrich Weigand @ 2012-12-05 17:09 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, Doug Evans, gdb-patches Tom Tromey wrote: > Ulrich> If I change the above filter to also accept "D", the test case > Ulrich> goes further. (It still ends up UNSUPPORTED, since it looks > Ulrich> like I don't have LZMA on the system ...). I'm not sure why the > Ulrich> filter for "T" is done; would it change something critical to > Ulrich> the test if "D" were added? > > I think it would be fine. OK, here's what I checked in. Thanks again! Bye, Ulrich ChangeLog: * gdb.base/gnu-debugdata.exp: Also include "D" symbols in ${binfile}.funcsyms list. Index: gdb/testsuite/gdb.base/gnu-debugdata.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/gnu-debugdata.exp,v retrieving revision 1.2 diff -u -p -r1.2 gnu-debugdata.exp --- gdb/testsuite/gdb.base/gnu-debugdata.exp 29 Nov 2012 20:53:24 -0000 1.2 +++ gdb/testsuite/gdb.base/gnu-debugdata.exp 5 Dec 2012 17:05:02 -0000 @@ -95,10 +95,12 @@ if {[pipeline "nm -D" \ } # Extract all the text (i.e. function) symbols from the debuginfo. +# (Note that we actually also accept "D" symbols, for the benefit +# of platforms like PowerPC64 that use function descriptors.) remote_file host delete ${binfile}.funcsyms if {[pipeline "nm" \ [list [transform nm] "${binfile} --format=posix --defined-only"] \ - [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\"||\\\$2==\"D\")print\\ \\\$1\\}"] \ [list sort "" "" "${binfile}.funcsyms"]]} { return -1 } -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-26 19:21 ` Tom Tromey 2012-11-26 22:24 ` Andrew Pinski 2012-11-29 19:19 ` Ulrich Weigand @ 2012-12-11 16:42 ` Yufeng Zhang 2 siblings, 0 replies; 42+ messages in thread From: Yufeng Zhang @ 2012-12-11 16:42 UTC (permalink / raw) To: gdb-patches; +Cc: Tom Tromey, Marcus Shawcroft Hi Tom, On 26/11/12 19:20, Tom Tromey wrote: > diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp > new file mode 100644 > index 0000000..f876309 [snip] > +# Extract the dynamic symbols from the main binary, there is no need > +# to also have these in the normal symbol table. > +remote_file host delete ${binfile}.dynsyms > +if {[pipeline "nm -D" \ > + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ > + [list awk "\\{print\\ \\\$1\\}"] \ > + [list sort "" "" "${binfile}.dynsyms"]]} { > + return -1 > +} The test can fail when there is no dynamic symbols in the binary file as 'nm' will return 1 with an error message of "No symbols"; binaries for baremetal targets usually don't have dynamic symbols. In such a case, I think the test should generate an empty ${binfile}.dynsyms and continue. Or maybe the tests should only be run for linux targets? > +# Inject the compressed data into the .gnu_debugdata section of the > +# original binary. > +remote_file host delete ${binfile}.mini_debuginfo.xz > +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { > + return -1 > +} This creates a dependency on 'xz'. I think either its availability should be checked before the test (and return UNSUPPORTED if 'xz' not found), or 'xz' should be documented as required in the section of "Requirements for Building GDB". Thanks, Yufeng ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-14 19:37 ` Doug Evans 2012-11-14 22:12 ` Joel Brobecker 2012-11-15 11:18 ` Pedro Alves @ 2012-11-16 20:04 ` Tom Tromey 2 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-16 20:04 UTC (permalink / raw) To: Doug Evans; +Cc: Pedro Alves, gdb-patches Doug> Does Redhat have a *formal* spec of .gnu_debugdata that says COFF, Doug> etc. is supported. [If that's the case then my point is moot, but Doug> I couldn't find any such formal spec.] No, there isn't one. There are only the docs in gdb.texinfo. Doug> 2) Can you add something like the following to the docs? Doug> This section is an LZMA compressed ELF file containing the Doug> standard ELF symbol and DWARF sections. It needn't, but may, Doug> contain full debug info. The intent is that it contains the Doug> desired subset of debug info that makes things like backtracing Doug> work without making the file too large. I've added some text, let me know what you think. Tom 2012-11-14 Alexander Larsson <alexl@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention mini debuginfo feature. * minidebug.c: New file. * configure.ac: Check for lzma. * configure, config.in: Rebuild. * Makefile.in (LIBLZMA): New variable. (CLIBS): Include LIBLZMA. (SFILES): Mention minidebug.c. (COMMON_OBS): Mention minidebug.o. * symfile.c (read_symbols): New function. (syms_from_objfile, reread_symbols): Call it. * symfile.h (find_separate_debug_file_in_section): Declare. 2012-11-14 Tom Tromey <tromey@redhat.com> * gdb.texinfo (MiniDebugInfo): New node. (GDB Files): Update. 2012-11-14 Jan Kratochvil <jan.kratochvil@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.base/gnu-debugdata.exp: New file. * gdb.base/gnu-debugdata.c: New file. * lib/gdb.exp (gdb_file_cmd): Handle LZMA warning. (gdb_unload): Return 0 on success. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index e9aeb0c..3dd7b85 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -151,6 +151,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@ # Where is expat? This will be empty if expat was not available. LIBEXPAT = @LIBEXPAT@ +# Where is lzma? This will be empty if lzma was not available. +LIBLZMA = @LIBLZMA@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -469,7 +472,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_ # LIBIBERTY appears twice on purpose. CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \ - $(LIBEXPAT) \ + $(LIBEXPAT) $(LIBLZMA) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -714,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inline-frame.c \ interps.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ - language.c linespec.c \ + language.c linespec.c minidebug.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ @@ -877,6 +880,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ filesystem.o \ inf-child.o \ interps.o \ + minidebug.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ diff --git a/gdb/NEWS b/gdb/NEWS index 9375218..803a898 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -93,6 +93,11 @@ show print type typedefs ** New optional parameter COUNT added to the "-data-write-memory-bytes" command, to allow pattern filling of memory areas. +* GDB now supports the "mini debuginfo" section, .gnu_debugdata. + You must have the LZMA library available when configuring GDB for this + feature to be enabled. For more information, see: + http://fedoraproject.org/wiki/Features/MiniDebugInfo + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/configure.ac b/gdb/configure.ac index 030fb06..9791143 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2053,6 +2053,27 @@ LIBS=$OLD_LIBS # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" +# If building on ELF, look for lzma support for embedded compressed debug info. +if test $gdb_cv_var_elf = yes; then + AC_ARG_WITH(lzma, + AS_HELP_STRING([--with-lzma], [support lzma compression (auto/yes/no)]), + [], [with_lzma=auto]) + AC_MSG_CHECKING([whether to use lzma]) + AC_MSG_RESULT([$with_lzma]) + + if test "${with_lzma}" != no; then + AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include "lzma.h"], + [lzma_index_iter iter; + lzma_index_iter_init (&iter, 0); + lzma_mf_is_supported (LZMA_MF_HC3);]) + if test "$HAVE_LIBLZMA" != yes; then + if test "$with_lzma" = yes; then + AC_MSG_ERROR([missing liblzma for --with-lzma]) + fi + fi + fi +fi + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" AC_SUBST(LIBGUI) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 945a66b..891fb89 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15865,6 +15865,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* MiniDebugInfo:: Debugging information in a special section * Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @@ -16790,6 +16791,60 @@ gnu_debuglink_crc32 (unsigned long crc, @noindent This computation does not apply to the ``build ID'' method. +@node MiniDebugInfo +@section Debugging information in a special section +@cindex separate debug sections +@cindex @samp{.gnu_debugdata} section + +Some systems ship pre-built executables and libraries that have a +special @samp{.gnu_debugdata} section. This feature is called +@dfn{MiniDebugInfo}. This section holds an LZMA-compressed object and +is used to supply extra symbols for backtraces. + +The object contained in this section is just a compressed object of +the same format as the object in which it is contained. For example, +if the executable is an ELF object, then the contents of +@samp{.gnu_debugdata} must be a compressed ELF object. + +The intent of this section is to provide extra minimal debugging +information for use in simple backtraces. It is not intended to be a +replacement for full separate debugging information (@pxref{Separate +Debug Files}). The example below shows the intended use; however, +@value{GDBN} does not currently put restrictions on what sort of +debugging information might be included in the section. + +@value{GDBN} has support for this extension. If the section exists, +then it is used provided that no other source of debugging information +can be found, and that @value{GDBN} was configured with LZMA support. + +This section can be easily created using @command{objcopy} and other +standard utilities: + +@smallexample +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table +nm -D @var{binary} --format=posix --defined-only \ + | awk '@{ print $1 @}' | sort > dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo . +nm @var{binary} --format=posix --defined-only \ + | awk '@{ if ($2 == "T" || $2 == "t") print $1 @}' \ + | sort > funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. +comm -13 dynsyms funcsyms > keep_symbols + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +objcopy -S --remove-section .gdb_index --remove-section .comment \ + --keep-symbols=keep_symbols @var{binary} mini_debuginfo + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +xz mini_debuginfo +objcopy --add-section .gnu_debugdata=mini_debuginfo.xz @var{binary} +@end smallexample @node Index Files @section Index Files Speed Up @value{GDBN} diff --git a/gdb/minidebug.c b/gdb/minidebug.c new file mode 100644 index 0000000..1b75ead --- /dev/null +++ b/gdb/minidebug.c @@ -0,0 +1,295 @@ +/* Read MiniDebugInfo data from an objfile. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_string.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" + +#ifdef HAVE_LIBLZMA + +#include <lzma.h> + +/* Allocator function for LZMA. */ + +static void * +alloc_lzma (void *opaque, size_t nmemb, size_t size) +{ + return xmalloc (nmemb * size); +} + +/* Free function for LZMA. */ + +static void +free_lzma (void *opaque, void *ptr) +{ + xfree (ptr); +} + +/* The allocator object for LZMA. Note that 'gdb_lzma_allocator' + cannot be const due to the lzma library function prototypes. */ + +static lzma_allocator gdb_lzma_allocator = { alloc_lzma, free_lzma, NULL }; + +/* Custom bfd_openr_iovec implementation to read compressed data from + a section. This keeps only the last decompressed block in memory + to allow larger data without using to much memory. */ + +struct lzma_stream +{ + /* Section of input BFD from which we are decoding data. */ + asection *section; + + /* lzma library decompression state. */ + lzma_index *index; + + /* Currently decoded block. */ + bfd_size_type data_start; + bfd_size_type data_end; + gdb_byte *data; +}; + +/* bfd_openr_iovec OPEN_P implementation for + find_separate_debug_file_in_section. OPEN_CLOSURE is 'asection *' + of the section to decompress. + + Return 'struct lzma_stream *' must be freed by caller by xfree, together + with its INDEX lzma data. */ + +static void * +lzma_open (struct bfd *nbfd, void *open_closure) +{ + asection *section = open_closure; + bfd_size_type size, offset; + lzma_stream_flags options; + gdb_byte footer[LZMA_STREAM_HEADER_SIZE]; + gdb_byte *indexdata; + lzma_index *index; + int ret; + uint64_t memlimit = UINT64_MAX; + struct lzma_stream *lstream; + size_t pos; + + size = bfd_get_section_size (section); + offset = section->filepos + size - LZMA_STREAM_HEADER_SIZE; + if (size < LZMA_STREAM_HEADER_SIZE + || bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (footer, LZMA_STREAM_HEADER_SIZE, section->owner) + != LZMA_STREAM_HEADER_SIZE + || lzma_stream_footer_decode (&options, footer) != LZMA_OK + || offset < options.backward_size) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + offset -= options.backward_size; + indexdata = xmalloc (options.backward_size); + index = NULL; + pos = 0; + if (bfd_seek (section->owner, offset, SEEK_SET) != 0 + || bfd_bread (indexdata, options.backward_size, section->owner) + != options.backward_size + || lzma_index_buffer_decode (&index, &memlimit, &gdb_lzma_allocator, + indexdata, &pos, options.backward_size) + != LZMA_OK + || lzma_index_size (index) != options.backward_size) + { + xfree (indexdata); + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + xfree (indexdata); + + lstream = xzalloc (sizeof (struct lzma_stream)); + lstream->section = section; + lstream->index = index; + + return lstream; +} + +/* bfd_openr_iovec PREAD_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static file_ptr +lzma_pread (struct bfd *nbfd, void *stream, void *buf, file_ptr nbytes, + file_ptr offset) +{ + struct lzma_stream *lstream = stream; + bfd_size_type chunk_size; + lzma_index_iter iter; + gdb_byte *compressed, *uncompressed; + file_ptr block_offset; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block; + size_t compressed_pos, uncompressed_pos; + file_ptr res; + + res = 0; + while (nbytes > 0) + { + if (lstream->data == NULL + || lstream->data_start > offset || offset >= lstream->data_end) + { + asection *section = lstream->section; + + lzma_index_iter_init (&iter, lstream->index); + if (lzma_index_iter_locate (&iter, offset)) + break; + + compressed = xmalloc (iter.block.total_size); + block_offset = section->filepos + iter.block.compressed_file_offset; + if (bfd_seek (section->owner, block_offset, SEEK_SET) != 0 + || bfd_bread (compressed, iter.block.total_size, section->owner) + != iter.block.total_size) + { + xfree (compressed); + break; + } + + uncompressed = xmalloc (iter.block.uncompressed_size); + + memset (&block, 0, sizeof (block)); + block.filters = filters; + block.header_size = lzma_block_header_size_decode (compressed[0]); + if (lzma_block_header_decode (&block, &gdb_lzma_allocator, compressed) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + compressed_pos = block.header_size; + uncompressed_pos = 0; + if (lzma_block_buffer_decode (&block, &gdb_lzma_allocator, + compressed, &compressed_pos, + iter.block.total_size, + uncompressed, &uncompressed_pos, + iter.block.uncompressed_size) + != LZMA_OK) + { + xfree (compressed); + xfree (uncompressed); + break; + } + + xfree (compressed); + + xfree (lstream->data); + lstream->data = uncompressed; + lstream->data_start = iter.block.uncompressed_file_offset; + lstream->data_end = (iter.block.uncompressed_file_offset + + iter.block.uncompressed_size); + } + + chunk_size = min (nbytes, lstream->data_end - offset); + memcpy (buf, lstream->data + offset - lstream->data_start, chunk_size); + buf = (gdb_byte *) buf + chunk_size; + offset += chunk_size; + nbytes -= chunk_size; + res += chunk_size; + } + + return res; +} + +/* bfd_openr_iovec CLOSE_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_close (struct bfd *nbfd, + void *stream) +{ + struct lzma_stream *lstream = stream; + + lzma_index_end (lstream->index, &gdb_lzma_allocator); + xfree (lstream->data); + xfree (lstream); + return 0; +} + +/* bfd_openr_iovec STAT_P implementation for + find_separate_debug_file_in_section. Passed STREAM + is 'struct lzma_stream *'. */ + +static int +lzma_stat (struct bfd *abfd, + void *stream, + struct stat *sb) +{ + struct lzma_stream *lstream = stream; + + sb->st_size = lzma_index_uncompressed_size (lstream->index); + return 0; +} + +#endif /* HAVE_LIBLZMA */ + +/* This looks for a xz compressed separate debug info object file embedded + in a section called .gnu_debugdata. See + http://fedoraproject.org/wiki/Features/MiniDebugInfo + or the "Separate Debug Sections" of the manual for details. + If we find one we create a iovec based bfd that decompresses the + object data on demand. If we don't find one, return NULL. */ + +bfd * +find_separate_debug_file_in_section (struct objfile *objfile) +{ + asection *section; + bfd *abfd; + + if (objfile->obfd == NULL) + return NULL; + + section = bfd_get_section_by_name (objfile->obfd, ".gnu_debugdata"); + if (section == NULL) + return NULL; + +#ifdef HAVE_LIBLZMA + abfd = gdb_bfd_openr_iovec (objfile->name, gnutarget, lzma_open, section, + lzma_pread, lzma_close, lzma_stat); + if (abfd == NULL) + return NULL; + + if (!bfd_check_format (abfd, bfd_object)) + { + warning (_("Cannot parse .gnu_debugdata section; not a BFD object")); + gdb_bfd_unref (abfd); + return NULL; + } + + if (bfd_get_flavour (objfile->obfd) != bfd_get_flavour (abfd)) + { + warning (_("Cannot parse .gnu_debugdata section; wrong file format")); + gdb_bfd_unref (abfd); + return NULL; + } +#else + warning (_("Cannot parse .gnu_debugdata section; LZMA support was " + "disabled at compile time")); + abfd = NULL; +#endif /* !HAVE_LIBLZMA */ + + return abfd; +} diff --git a/gdb/symfile.c b/gdb/symfile.c index 55af541..6a2fc89 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -876,6 +876,27 @@ default_symfile_segments (bfd *abfd) return data; } +/* This is a convenience function to call sym_read for OBJFILE and + possibly force the partial symbols to be read. */ + +static void +read_symbols (struct objfile *objfile, int add_flags) +{ + (*objfile->sf->sym_read) (objfile, add_flags); + if (!objfile_has_partial_symbols (objfile)) + { + bfd *abfd = find_separate_debug_file_in_section (objfile); + struct cleanup *cleanup = make_cleanup_bfd_unref (abfd); + + if (abfd != NULL) + symbol_file_add_separate (abfd, add_flags, objfile); + + do_cleanups (cleanup); + } + if ((add_flags & SYMFILE_NO_READ) == 0) + require_partial_symbols (objfile, 0); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -996,10 +1017,7 @@ syms_from_objfile (struct objfile *objfile, init_objfile_sect_indices (objfile); } - (*objfile->sf->sym_read) (objfile, add_flags); - - if ((add_flags & SYMFILE_NO_READ) == 0) - require_partial_symbols (objfile, 0); + read_symbols (objfile, add_flags); /* Discard cleanups as symbol reading was successful. */ @@ -2601,14 +2619,9 @@ reread_symbols (void) (*objfile->sf->sym_init) (objfile); clear_complaints (&symfile_complaints, 1, 1); - /* Do not set flags as this is safe and we don't want to be - verbose. */ - (*objfile->sf->sym_read) (objfile, 0); - if ((objfile->flags & OBJF_PSYMTABS_READ) != 0) - { - objfile->flags &= ~OBJF_PSYMTABS_READ; - require_partial_symbols (objfile, 0); - } + + objfile->flags &= ~OBJF_PSYMTABS_READ; + read_symbols (objfile, 0); if (!objfile_has_symbols (objfile)) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bb75c18..223f874 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -690,4 +690,8 @@ extern void elfmdebug_build_psymtabs (struct objfile *, const struct ecoff_debug_swap *, asection *); +/* From minidebug.c. */ + +extern bfd *find_separate_debug_file_in_section (struct objfile *); + #endif /* !defined(SYMFILE_H) */ diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.c b/gdb/testsuite/gdb.base/gnu-debugdata.c new file mode 100644 index 0000000..b8b7e8a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 <signal.h> + +static int +debugdata_function (void) +{ + return raise (SIGSEGV) + 1; +} + +int +main (void) +{ + return debugdata_function () + 1; +} diff --git a/gdb/testsuite/gdb.base/gnu-debugdata.exp b/gdb/testsuite/gdb.base/gnu-debugdata.exp new file mode 100644 index 0000000..f876309 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-debugdata.exp @@ -0,0 +1,157 @@ +# Copyright 2012 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/>. + +standard_testfile + +if [build_executable ${testfile}.exp $testfile] { + return -1 +} + +# A wrapper for 'remote_exec host' that passes or fails a test. +# Returns 0 if all went well, nonzero on failure. +# TEST is the name of the test, other arguments are as for +# remote_exec. +proc run {test program args} { + verbose "cmdline is remote_exec host $program $args" + # remote_exec doesn't work properly if the output is set but the + # input is the empty string -- so replace an empty input with + # /dev/null. + if {[llength $args] > 1 && [lindex $args 1] == ""} { + set args [lreplace $args 1 1 "/dev/null"] + } + set result [eval remote_exec host [list $program] $args] + verbose "result is $result" + lassign $result status output + if {$status == 0} { + pass $test + return 0 + } else { + fail $test + return -1 + } +} + +set pipeline_counter 0 + +# Run a pipeline of processes through 'run'. +# TEST is the base name of the test, it is modified and passed to 'run'. +# Each subsequent argument is a list of the form {PROGRAM [ARG]...}. +# It is passed to 'run'. However, before being passed, if input and output +# files are not specified in the list, then this proc provides them. +# Each program in the pipeline takes its input from the previous +# program's output. +proc pipeline {test args} { + global pipeline_counter + + set input_file {} + foreach arglist $args { + verbose "raw args are $arglist" + lassign $arglist program arguments input output + + if {$input == ""} { + set input $input_file + } + if {$output == ""} { + set output [standard_output_file pipe.[pid].$pipeline_counter] + incr pipeline_counter + } + verbose "cooked args are [list $program $arguments $input $output]" + + if {[run "$test - invoke $program" $program $arguments \ + $input $output]} { + return -1 + } + + set input_file $output + } + return 0 +} + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. +remote_file host delete ${binfile}.dynsyms +if {[pipeline "nm -D" \ + [list [transform nm] "-D ${binfile} --format=posix --defined-only"] \ + [list awk "\\{print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.dynsyms"]]} { + return -1 +} + +# Extract all the text (i.e. function) symbols from the debuginfo. +remote_file host delete ${binfile}.funcsyms +if {[pipeline "nm" \ + [list [transform nm] "${binfile} --format=posix --defined-only"] \ + [list awk "\\{if(\\\$2==\"T\"||\\\$2==\"t\")print\\ \\\$1\\}"] \ + [list sort "" "" "${binfile}.funcsyms"]]} { + return -1 +} + +# Keep all the function symbols not already in the dynamic symbol +# table. +remote_file host delete ${binfile}.keep_symbols +if {[run "comm" "comm" "-13 ${binfile}.dynsyms ${binfile}.funcsyms" "" \ + "${binfile}.keep_symbols"]} { + return -1 +} + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. +remote_file host delete ${binfile}.mini_debuginfo +if {[run "objcopy 1" [transform objcopy] "-S --remove-section .gdb_index --remove-section .comment --keep-symbols=${binfile}.keep_symbols ${binfile} ${binfile}.mini_debuginfo"]} { + return -1 +} + +# GDB specific - we do not have split executable in advance. +remote_file host delete ${binfile}.strip +if {[run "strip" [transform strip] \ + "--strip-all -o ${binfile}.strip ${binfile}"]} { + return -1 +} + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. +remote_file host delete ${binfile}.mini_debuginfo.xz +if {[run "xz" "xz" "${binfile}.mini_debuginfo"]} { + return -1 +} +remote_file host delete ${binfile}.test +if {[run "objcopy 2" [transform objcopy] "--add-section .gnu_debugdata=${binfile}.mini_debuginfo.xz ${binfile}.strip ${binfile}.test"]} { + return -1 +} + +clean_restart "$testfile.strip" + +gdb_test "p debugdata_function" \ + {No symbol table is loaded\. Use the "file" command\.} \ + "no symtab" + +clean_restart "$testfile.test" + +if {$gdb_file_cmd_debug_info == "lzma"} { + unsupported "LZMA support not available in this gdb" +} else { + gdb_test "p debugdata_function" \ + { = {<text variable, no debug info>} 0x[0-9a-f]+ <debugdata_function>} \ + "have symtab" +} + +# Be sure to test the 'close' method on the MiniDebugInfo BFD. +if {[gdb_unload]} { + fail "unload MiniDebugInfo" +} else { + pass "unload MiniDebugInfo" +} + +gdb_exit diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 16e8b54..781ccc8 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -128,6 +128,7 @@ proc gdb_version { } { # # gdb_unload -- unload a file if one is loaded +# Return 0 on success, -1 on error. # proc gdb_unload {} { @@ -152,6 +153,7 @@ proc gdb_unload {} { return -1 } } + return 0 } # Many of the tests depend on setting breakpoints at various places and @@ -1278,6 +1280,8 @@ proc default_gdb_exit {} { # # debug file was loaded successfully and has debug information # nodebug file was loaded successfully and has no debug information +# lzma file was loaded, .gnu_debugdata found, but no LZMA support +# compiled in # fail file was not loaded # # I tried returning this information as part of the return value, @@ -1325,6 +1329,11 @@ proc gdb_file_cmd { arg } { send_gdb "file $arg\n" gdb_expect 120 { + -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" { + verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available" + set gdb_file_cmd_debug_info "lzma" + return 0 + } -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into $GDB with no debugging symbols" set gdb_file_cmd_debug_info "nodebug" ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey ` (3 preceding siblings ...) 2012-11-12 16:28 ` Tom Tromey @ 2012-11-12 21:26 ` Doug Evans 2012-11-13 17:43 ` Tom Tromey 2012-11-13 15:44 ` Jan Kratochvil 5 siblings, 1 reply; 42+ messages in thread From: Doug Evans @ 2012-11-12 21:26 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On Fri, Nov 9, 2012 at 9:33 AM, Tom Tromey <tromey@redhat.com> wrote: > Fedora recently approved and committed the "MiniDebuginfo" feature: > > http://fedoraproject.org/wiki/Features/MiniDebugInfo My eyesight must be worse than I think, I can find no docs on the technical specs of this. :-) Got url? ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-12 21:26 ` Doug Evans @ 2012-11-13 17:43 ` Tom Tromey 0 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-13 17:43 UTC (permalink / raw) To: Doug Evans; +Cc: gdb-patches >>>>> "Doug" == Doug Evans <dje@google.com> writes: Doug> My eyesight must be worse than I think, I can find no docs on the Doug> technical specs of this. :-) Doug> Got url? I don't think there are any aside from what I put in the manual. I can add some more text. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey ` (4 preceding siblings ...) 2012-11-12 21:26 ` Doug Evans @ 2012-11-13 15:44 ` Jan Kratochvil 2012-11-13 18:34 ` Tom Tromey 5 siblings, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2012-11-13 15:44 UTC (permalink / raw) To: gdb-patches; +Cc: Tom Tromey On Fri, 09 Nov 2012 18:33:27 +0100, Tom Tromey wrote: > Fedora recently approved and committed the "MiniDebuginfo" feature: > > http://fedoraproject.org/wiki/Features/MiniDebugInfo Just giving a feedback I have never agreed with this feature, there were many mails by me (and others) with subject /minidebuginfo/i: http://lists.fedoraproject.org/pipermail/devel/2012-May/thread.html And some Fedora developers still disagree with this (accepted now) feature. In summary the countercase is that build-id (already present in Fedora) supersedes this "large" .gnu_debugdata data pack. But people and their use cases differ a lot and sometimes this or that feature fits better. Regards, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: handle "MiniDebuginfo" section 2012-11-13 15:44 ` Jan Kratochvil @ 2012-11-13 18:34 ` Tom Tromey 0 siblings, 0 replies; 42+ messages in thread From: Tom Tromey @ 2012-11-13 18:34 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes: Jan> Just giving a feedback I have never agreed with this feature, there Jan> were many mails by me (and others) with subject /minidebuginfo/i: I'm not particularly fond of it either, but my rationale for putting it into gdb is that it is shipping in Fedora, and so this patch makes the upstream gdb as capable as the Fedora gdb in this area. Tom ^ permalink raw reply [flat|nested] 42+ messages in thread
end of thread, other threads:[~2012-12-11 16:42 UTC | newest] Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-11-09 17:33 RFA: handle "MiniDebuginfo" section Tom Tromey 2012-11-09 18:07 ` Eli Zaretskii 2012-11-09 18:13 ` Pedro Alves 2012-11-09 21:28 ` Tom Tromey 2012-11-13 12:56 ` Pedro Alves 2012-11-13 15:26 ` Pedro Alves 2012-11-13 18:32 ` Tom Tromey 2012-11-09 18:23 ` Joel Brobecker 2012-11-09 18:53 ` Pedro Alves 2012-11-09 19:13 ` Tom Tromey 2012-11-12 16:04 ` Tom Tromey 2012-11-12 17:04 ` Joel Brobecker 2012-11-12 18:24 ` Tom Tromey 2012-11-12 16:28 ` Tom Tromey 2012-11-13 18:36 ` Tom Tromey 2012-11-13 18:42 ` Eli Zaretskii 2012-11-13 19:12 ` Pedro Alves 2012-11-13 20:57 ` Tom Tromey 2012-11-14 16:13 ` Tom Tromey 2012-11-14 16:19 ` Pedro Alves 2012-11-14 16:59 ` Tom Tromey 2012-11-14 19:37 ` Doug Evans 2012-11-14 22:12 ` Joel Brobecker 2012-11-15 11:18 ` Pedro Alves 2012-11-16 19:51 ` Tom Tromey 2012-11-19 14:41 ` Pedro Alves 2012-11-26 19:21 ` Tom Tromey 2012-11-26 22:24 ` Andrew Pinski 2012-11-27 2:23 ` Tom Tromey 2012-11-29 19:19 ` Ulrich Weigand 2012-11-29 19:23 ` Tom Tromey 2012-11-29 19:33 ` Ulrich Weigand 2012-11-29 20:51 ` Tom Tromey 2012-11-30 14:05 ` Ulrich Weigand 2012-11-30 20:59 ` Tom Tromey 2012-12-05 17:09 ` Ulrich Weigand 2012-12-11 16:42 ` Yufeng Zhang 2012-11-16 20:04 ` Tom Tromey 2012-11-12 21:26 ` Doug Evans 2012-11-13 17:43 ` Tom Tromey 2012-11-13 15:44 ` Jan Kratochvil 2012-11-13 18:34 ` Tom Tromey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox