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


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"


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