* 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 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: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 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-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: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
` (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-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-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-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-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-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
* 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-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-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
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