From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7127 invoked by alias); 26 Nov 2012 22:24:36 -0000 Received: (qmail 7098 invoked by uid 22791); 26 Nov 2012 22:24:35 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,KAM_STOCKTIP,KHOP_RCVD_TRUST,KHOP_THREADED,RCVD_IN_DNSWL_LOW,RCVD_IN_HOSTKARMA_YE,TW_BJ,TW_BL,TW_CP,TW_XZ X-Spam-Check-By: sourceware.org Received: from mail-wg0-f43.google.com (HELO mail-wg0-f43.google.com) (74.125.82.43) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 26 Nov 2012 22:24:22 +0000 Received: by mail-wg0-f43.google.com with SMTP id dq12so4642875wgb.12 for ; Mon, 26 Nov 2012 14:24:20 -0800 (PST) MIME-Version: 1.0 Received: by 10.216.204.32 with SMTP id g32mr4872100weo.79.1353968660593; Mon, 26 Nov 2012 14:24:20 -0800 (PST) Received: by 10.217.64.194 with HTTP; Mon, 26 Nov 2012 14:24:20 -0800 (PST) In-Reply-To: <871ufggoh9.fsf@fleche.redhat.com> References: <87wqxuel5k.fsf@fleche.redhat.com> <87zk2mbym3.fsf@fleche.redhat.com> <877gpp8i67.fsf@fleche.redhat.com> <50A29B8B.7050606@redhat.com> <87r4nx5ih1.fsf@fleche.redhat.com> <87390c40ys.fsf@fleche.redhat.com> <20643.62177.106208.211209@ruffy2.mtv.corp.google.com> <50A4CF6D.40207@redhat.com> <87r4nttjgl.fsf@fleche.redhat.com> <50AA44F4.9020609@redhat.com> <871ufggoh9.fsf@fleche.redhat.com> Date: Mon, 26 Nov 2012 22:24:00 -0000 Message-ID: Subject: Re: RFA: handle "MiniDebuginfo" section From: Andrew Pinski To: Tom Tromey Cc: Pedro Alves , Doug Evans , gdb-patches@sourceware.org Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-11/txt/msg00694.txt.bz2 On Mon, Nov 26, 2012 at 11:20 AM, Tom Tromey wrote: >>>>>> "Pedro" == Pedro Alves 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 > Jan Kratochvil > Tom Tromey > > * 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 > > * gdb.texinfo (MiniDebugInfo): New node. > (GDB Files): Update. > > 2012-11-26 Jan Kratochvil > Tom Tromey > > * 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 > 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 . */ > + > +#include "defs.h" > +#include "gdb_bfd.h" > +#include "gdb_string.h" > +#include "symfile.h" > +#include "objfiles.h" > +#include "gdbcore.h" > + > +#ifdef HAVE_LIBLZMA > + > +#include > + > +/* 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 . */ > + > +#include > + > +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 . > + > +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" \ > + { = {} 0x[0-9a-f]+ } \ > + "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"