From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 82152 invoked by alias); 1 May 2015 14:40:33 -0000 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 Received: (qmail 82133 invoked by uid 89); 1 May 2015 14:40:31 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.3 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 X-HELO: homiemail-a78.g.dreamhost.com Received: from sub5.mail.dreamhost.com (HELO homiemail-a78.g.dreamhost.com) (208.113.200.129) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 01 May 2015 14:40:29 +0000 Received: from homiemail-a78.g.dreamhost.com (localhost [127.0.0.1]) by homiemail-a78.g.dreamhost.com (Postfix) with ESMTP id 2D28120004E2D for ; Fri, 1 May 2015 07:40:27 -0700 (PDT) Received: from vm-fedora21.eagercon.com (c-24-7-16-38.hsd1.ca.comcast.net [24.7.16.38]) (using TLSv1 with cipher ECDHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: eager@eagerm.com) by homiemail-a78.g.dreamhost.com (Postfix) with ESMTPSA id 109AB20004745 for ; Fri, 1 May 2015 07:40:27 -0700 (PDT) Message-ID: <5543905A.1040108@eagerm.com> Date: Fri, 01 May 2015 14:40:00 -0000 From: Michael Eager User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 MIME-Version: 1.0 To: "gdb-patches@sourceware.org" Subject: Re: [PATCH] Support gzip compressed exec and core files in gdb References: <54FF77D6.7010400@eagerm.com> In-Reply-To: <54FF77D6.7010400@eagerm.com> Content-Type: multipart/mixed; boundary="------------030903010609000505000401" X-IsSubscribed: yes X-SW-Source: 2015-05/txt/msg00007.txt.bz2 This is a multi-part message in MIME format. --------------030903010609000505000401 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1075 On 03/10/2015 04:01 PM, Michael Eager wrote: > Add support to automatically unzip compressed executable and core files. > Files will be uncompressed into temporary directory (/tmp or $TMPDIR) > and are deleted when GDB exits. This should be transparent to users, > except for disk space requirements. The name of the uncompressed file is > mentioned, but all references to the file in GDB messages is to the file > which the user specified. Attached is a revised patch. I discovered a logic error after refactoring the code. gdb/ChangeLog: * utils.c (struct compressed_file_cache_search, eq_compressed_file, is_gzip, decompress_gzip, do_compressed_cleanup, identify_compression, uncompress_to_temporar, gdb_uncompress): New. * utils.h (gdb_uncompress): Declare. * corelow.c (core_open): Uncompress core file. * exec.c (exec_file_attach): Uncompress exec file. * symfile.c (symfile_bfd_open): Uncompress sym (exec) file. * NEWS: Mention new functionality. -- Michael Eager eager@eagercon.com 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077 --------------030903010609000505000401 Content-Type: text/x-patch; name="0001-GDB-support-compressed-exec-and-core-files.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0001-GDB-support-compressed-exec-and-core-files.patch" Content-length: 12137 =46rom 9e8ffc3d0a5472cc6e1c48ebf90641f79157fc8a Mon Sep 17 00:00:00 2001 From: Michael Eager Date: Fri, 10 Apr 2015 11:55:02 -0700 Subject: [PATCH] GDB support compressed exec and core files. Add support to automatically unzip compressed executable and core files. Files will be uncompressed into temporary directory (/tmp or $TMPDIR) and are deleted when GDB exits. This should be transparent to users, except for disk space requirements. The name of the uncompressed file is mentioned, but all references to the file in GDB messages is to the file which the user specified. gdb/ChangeLog: * utils.c (struct compressed_file_cache_search, eq_compressed_file, is_gzip, decompress_gzip, do_compressed_cleanup, identify_compression, uncompress_to_temporar, gdb_uncompress): New. * utils.h (gdb_uncompress): Declare. * corelow.c (core_open): Uncompress core file. * exec.c (exec_file_attach): Uncompress exec file. * symfile.c (symfile_bfd_open): Uncompress sym (exec) file. * NEWS: Mention new functionality. gdb/doc: * gdb.texinfo (Files): Mention gzipped exec and core files. --- gdb/NEWS | 3 + gdb/corelow.c | 11 ++- gdb/doc/gdb.texinfo | 5 ++ gdb/exec.c | 14 +++- gdb/symfile.c | 14 +++- gdb/utils.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++= ++++ gdb/utils.h | 4 + 7 files changed, 259 insertions(+), 3 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 651401d..2c59236 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -139,6 +139,9 @@ qXfer:exec-file:read =20 * Removed targets and native configurations =20 +* GDB will automatically uncompress executable and core files + which have been compressed using gzip. + HP/PA running HP-UX hppa*-*-hpux* Itanium running HP-UX ia64-*-hpux* =20 diff --git a/gdb/corelow.c b/gdb/corelow.c index 9218003..8211595 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -279,6 +279,7 @@ core_open (const char *arg, int from_tty) int scratch_chan; int flags; char *filename; + char *uncompressed_filename; =20 target_preopen (from_tty); if (!arg) @@ -310,12 +311,20 @@ core_open (const char *arg, int from_tty) if (scratch_chan < 0) perror_with_name (filename); =20 - temp_bfd =3D gdb_bfd_fopen (filename, gnutarget,=20 + temp_bfd =3D gdb_bfd_fopen (filename, gnutarget, write_files ? FOPEN_RUB : FOPEN_RB, scratch_chan); if (temp_bfd =3D=3D NULL) perror_with_name (filename); =20 + if (!write_files && gdb_uncompress (filename, &uncompressed_filename)) + { + close (scratch_chan); + scratch_chan =3D gdb_open_cloexec (uncompressed_filename, flags, 0); + temp_bfd =3D gdb_bfd_fopen (uncompressed_filename, gnutarget, + FOPEN_RB, scratch_chan); + } + if (!bfd_check_format (temp_bfd, bfd_core) && !gdb_check_format (temp_bfd)) { diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 2ce2e57..a82a55b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -17504,6 +17504,11 @@ via @code{gdbserver} (@pxref{Server, file, Using t= he @code{gdbserver} Program}). In these situations the @value{GDBN} commands to specify new files are useful. =20 +Executable and core files may be compressed using @command{gzip}. These +files will be uncompressed into temporary files in the system-wide +temporary directory (e.g., @file{/tmp} on some systems). The files will +have a unique name and will be deleted when @value{GDBN} terminates. + @table @code @cindex executable file @kindex file diff --git a/gdb/exec.c b/gdb/exec.c index 4e079fd..2eba1bb 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -196,6 +196,7 @@ void exec_file_attach (const char *filename, int from_tty) { struct cleanup *cleanups; + char *uncompressed_filename =3D NULL; =20 /* First, acquire a reference to the current exec_bfd. We release this at the end of the function; but acquiring it now lets the @@ -280,7 +281,18 @@ exec_file_attach (const char *filename, int from_tty) exec_bfd =3D gdb_bfd_fopen (canonical_pathname, gnutarget, FOPEN_RUB, scratch_chan); else - exec_bfd =3D gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan); + { + if (!gdb_uncompress (canonical_pathname, &uncompressed_filename)) + exec_bfd =3D gdb_bfd_open (canonical_pathname, gnutarget, scratch_cha= n); + else + { + close (scratch_chan); + scratch_chan =3D openp ("", 0, uncompressed_filename, + O_RDONLY | O_BINARY, &scratch_pathname); + + exec_bfd =3D gdb_bfd_open (uncompressed_filename, gnutarget, scratc= h_chan); + } + } =20 if (!exec_bfd) { diff --git a/gdb/symfile.c b/gdb/symfile.c index 0c35ffa..43c0522 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -56,6 +56,7 @@ #include "stack.h" #include "gdb_bfd.h" #include "cli/cli-utils.h" +#include "utils.h" =20 #include #include @@ -1723,6 +1724,8 @@ symfile_bfd_open (const char *name) bfd *sym_bfd; int desc =3D -1; struct cleanup *back_to =3D make_cleanup (null_cleanup, 0); + char *absolute_name; + char *uncompressed_filename; =20 if (!is_target_filename (name)) { @@ -1756,7 +1759,16 @@ symfile_bfd_open (const char *name) name =3D absolute_name; } =20 - sym_bfd =3D gdb_bfd_open (name, gnutarget, desc); + if (!gdb_uncompress (name, &uncompressed_filename)) + sym_bfd =3D gdb_bfd_open (name, gnutarget, desc); + else + { + close (desc); + desc =3D openp ("", 0, uncompressed_filename, O_RDONLY | O_BINARY, &= absolute_name); + + sym_bfd =3D gdb_bfd_open (uncompressed_filename, gnutarget, desc); + } + if (!sym_bfd) error (_("`%s': can't open to read symbols: %s."), name, bfd_errmsg (bfd_get_error ())); diff --git a/gdb/utils.c b/gdb/utils.c index aaaf9c5..4160c54 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -29,6 +29,8 @@ #include #endif /* HAVE_SYS_RESOURCE_H */ =20 +#include + #ifdef TUI #include "tui/tui.h" /* For tui_get_command_dimension. */ #endif @@ -126,6 +128,10 @@ int immediate_quit; as octal escapes. Zero means just print the value (e.g. it's an international character, and the terminal or window can cope.) */ =20 +/* Type of file compression. */ + +enum file_compression_t {NONE, GZIP, BZIP2}; + int sevenbit_strings =3D 0; static void show_sevenbit_strings (struct ui_file *file, int from_tty, @@ -3479,6 +3485,211 @@ gdb_filename_fnmatch (const char *pattern, const ch= ar *string, int flags) =20 return fnmatch (pattern, string, flags); } +=0C +/* Hash table of compressed files. */ + +static htab_t compressed_file_cache; + +struct compressed_file_cache_search +{ + char *filename; + char *uncompressed_filename; + time_t mtime; +}; + +static int +eq_compressed_file (const void *a, const void *b) +{ + const struct compressed_file_cache_search *entry =3D a; + const struct compressed_file_cache_search *search =3D b; + + return (strcmp (entry->filename, search->filename) =3D=3D 0); +} + +/* Test if file is compressed with gzip. */ + +static inline int +is_gzip (unsigned char *buf) +{ + return (buf[0] =3D=3D 037 && buf[1] =3D=3D 0213); /* From /usr/share/mag= ic. */ +} + +/* Alloc 1Mb buffer to uncompress data. */ +#define COMPRESS_BUF_SIZE (1024 * 1024) +static int +decompress_gzip (const char *filename, FILE *tmp) +{ + char *buf =3D xmalloc (COMPRESS_BUF_SIZE); + gzFile compressed =3D gzopen (filename, "r"); + int count, res; + + if (buf =3D=3D NULL || compressed =3D=3D NULL) + { + fprintf_filtered (gdb_stderr, _("error copying gzip file\n")); + free (buf); + return 0; + } + + while ((count =3D gzread (compressed, buf, COMPRESS_BUF_SIZE))) + { + res =3D fwrite (buf, 1, count, tmp); + if (res !=3D count) + { + fprintf_filtered (gdb_stderr, _("error decompressing gzip file\n")); + free (buf); + return 0; + } + } + + gzclose (compressed); + free (buf); + return 1; +} + +/* Delete uncompressed temp file when terminating. */ +static void +do_compressed_cleanup (void *filename) +{ + unlink (filename); + xfree (filename); +} + +/* Identify type of file compression used. */ +static enum file_compression_t +identify_compression (const char *filename) +{ + FILE *handle; + enum file_compression_t file_compression =3D NONE; + unsigned char buffer[1024]; + size_t count; + + handle =3D fopen (filename, FOPEN_RB); + if (handle =3D=3D NULL) + return 0; + + count =3D fread (buffer, 1, sizeof buffer, handle); + if (count > 0) + { + if (is_gzip (buffer)) + file_compression =3D GZIP; + } + + fclose (handle); + + return file_compression; +} + +/* Uncompress into temporary file. Return temp file name. */ +static char * +uncompress_to_temporary (const char *filename) +{ + enum file_compression_t file_compression; + char *template; + int ret =3D 0; + int decomp_fd; + FILE *decomp_file; + + file_compression =3D identify_compression (filename); + if (file_compression !=3D GZIP) + /* Only gzip supported at this time. */ + return NULL; + + /* Create temporary file name for uncompressed file. */ + if (!asprintf (&template, "%s%s-XXXXXX", choose_tmpdir (), + basename (filename))) + return NULL; + + decomp_fd =3D mkstemp (template); + if (decomp_fd =3D=3D -1) + return NULL; + + decomp_file =3D fdopen (decomp_fd, FOPEN_WUB); + + if (file_compression =3D=3D GZIP) + { + printf (_("Decompressing %s to %s\n"), filename, template); + ret =3D decompress_gzip (filename, decomp_file); + } + + if (!ret) + { + xfree (template); + template =3D NULL; + } + + fclose (decomp_file); + return template; +} + +/* If file is compressed, uncompress it into a temporary. */ +int +gdb_uncompress (const char *filename, char **uncompressed_filename) +{ + struct compressed_file_cache_search search, *found; + struct stat st; + hashval_t hash; + void **slot; + char *temp_filename; + + if (compressed_file_cache =3D=3D NULL) + compressed_file_cache =3D htab_create_alloc (1, htab_hash_string, + eq_compressed_file, + NULL, xcalloc, xfree); + if (stat (filename, &st) < 0) + return 0; + + search.filename =3D (char *) filename; + search.uncompressed_filename =3D NULL; + + hash =3D htab_hash_string (filename); + found =3D htab_find_with_hash (compressed_file_cache, &search, hash); + + if (found) + { + /* We previously uncompressed the file. */ + if (found->mtime =3D=3D st.st_mtime) + { + /* Return file if compressed file not changed. */ + *uncompressed_filename =3D found->uncompressed_filename; + return 1; + } + else + { + /* Delete old uncompressed file. */ + unlink (found->uncompressed_filename); + xfree (found->filename); + xfree (found->uncompressed_filename); + } + } + + temp_filename =3D uncompress_to_temporary (filename); + + if (!temp_filename) + /* Not uncompressed. */ + return 0; + + if (!found) + { + slot =3D htab_find_slot_with_hash (compressed_file_cache, + &search, hash, INSERT); + gdb_assert (slot && !*slot); + found =3D xmalloc (sizeof (struct compressed_file_cache_search)); + *slot =3D found; + } + + found->filename =3D strdup (filename); + found->mtime =3D st.st_mtime; + found->uncompressed_filename =3D temp_filename; + + /* Tell caller name of uncompressed file. */ + *uncompressed_filename =3D temp_filename; + + /* Schedule delete of temp file when gdb ends. */ + make_final_cleanup (do_compressed_cleanup, xstrdup (temp_filename)); + + return 1; +} +=0C =20 /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_utils; diff --git a/gdb/utils.h b/gdb/utils.h index cae1ac0..883e4c6 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -371,4 +371,8 @@ extern void dump_core (void); =20 extern char *make_hex_string (const gdb_byte *data, size_t length); =20 +/* Uncompress file if compressed. */ + +int gdb_uncompress (const char *filename, char **uncompressed_filename); + #endif /* UTILS_H */ --=20 2.2.1 --------------030903010609000505000401--