From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27151 invoked by alias); 26 Nov 2012 19:21:12 -0000 Received: (qmail 27139 invoked by uid 22791); 26 Nov 2012 19:21:09 -0000 X-SWARE-Spam-Status: No, hits=-3.8 required=5.0 tests=AWL,BAYES_00,KAM_STOCKTIP,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_BJ,TW_BL,TW_CP,TW_XZ X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 26 Nov 2012 19:21:02 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id qAQJKxln013119 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 26 Nov 2012 14:20:59 -0500 Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id qAQJKoIf009358 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Mon, 26 Nov 2012 14:20:53 -0500 From: Tom Tromey To: Pedro Alves Cc: Doug Evans , gdb-patches@sourceware.org Subject: Re: RFA: handle "MiniDebuginfo" section 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> Date: Mon, 26 Nov 2012 19:21:00 -0000 In-Reply-To: <50AA44F4.9020609@redhat.com> (Pedro Alves's message of "Mon, 19 Nov 2012 14:40:52 +0000") Message-ID: <871ufggoh9.fsf@fleche.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain 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/msg00684.txt.bz2 >>>>> "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. 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"