This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: handle "MiniDebuginfo" section


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"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]