This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: Patch to handle compressed sections
} Neat. Out of curiosity, does this approach work well in practice?
Yes, it seems to work quite well.
} If you need to compress debug info, it means you are dealing with a
} very large amount of it.
This is true. An example binary we deal with could be about 2G with
debug information, and about 1.3G with the debug information
compressed.
However, we tend to have machines with quite fast processors, and
decompressing the debug information doesn't take very long; at least,
it's on the order of existing gdb startup time (which includes reading
all that data from disk in the first place). It may even be faster to
read less data from disk and uncompress it, than to just read all the
data from disk in the first place.
I wrote the patch to be extensible to other compression formats in the
future. One possibility would be to support a compression format that
does not have great compression, but is very fast to decompress. That
could be used in environments where decompress time is more of a
concern.
} It's a trade-off where you ease the burden on the computer where the
} program runs, and permits you to have debuginfo around where you
} probably couldn't before, but on the other hand you need a lot of
} resources to actually be able to work with that debuginfo in a debug
} environment, right?
I see the trade-off as more of a disk/cpu tradeoff. For us, the
machines are powerful enough to deal with the uncompressed binaries,
but they take up an awful lot of disk space. Compressing allows the
binaries to take up less disk, without really affecting run-time
behavior noticeably.
} Encoding this information in the section name looks strange to
} me. Isn't it possible to define a new flag in the section's sh_flags
} to signal that the section is compressed and then use the first few
} bytes of the section contents for the information above?
This was the first thing I tried, but it had -- as you pointed out --
compatibility issues. In particular, various tools would try to read
a .debug_* section, but not know about the new flag (or the new .note
section, if we implemented it that way), and would complain about a
malformed section. objdump, if I remember correctly, would complain
about 1000 times per malformed section(!).
I've found these tools deal much better if the section is just missing
entirely (because instead we have a section named .debug_*.zlib.nnnn
instead).
We could compromise and still give the section a different name, like
.debug_info.zlib, and then store the 'nnnn' part in a .note section or
somewhere else, but I didn't see much benefit to that.
} I think it's better for this error message to say something along
} the lines of "Support for compressed DWARF data is disabled in this
} copy of GDB".
Good idea. I attach a new patch below that's identical except for the
error mesage text.
craig
2008-03-24 Craig Silverstein <csilvers@google.com>
* configure.ac (AC_SEARCH_LIBS): Add check for zlib.
* config.in, configure: Regenerate.
* dwarf2read.c: Include zlib.h if present.
(uncompressed_section_size): New.
(section_is_p): New.
(dwarf2_locate_sections): Use section_is_p instead of strcmp
to determine whether a given section has a given name.
(dwarf2_read_section): Read the compressed section if present
in the binary.
--- gdb/config.in 2008-03-25 15:53:56.000000000 -0700
+++ gdb/config.in 2008-03-24 15:50:21.000000000 -0700
@@ -472,6 +472,9 @@
/* Define to 1 if you have the `XML_StopParser' function. */
#undef HAVE_XML_STOPPARSER
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
/* Define to 1 if your system has the _etext variable. */
#undef HAVE__ETEXT
--- gdb/configure 2008-03-25 15:53:56.000000000 -0700
+++ gdb/configure 2008-03-24 15:50:23.000000000 -0700
@@ -6003,6 +6003,283 @@
fi
+# Link in zlib if we can. This allows us to read compressed debug sections.
+echo "$as_me:$LINENO: checking for library containing zlibVersion" >&5
+echo $ECHO_N "checking for library containing zlibVersion... $ECHO_C" >&6
+if test "${ac_cv_search_zlibVersion+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_zlibVersion=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char zlibVersion ();
+int
+main ()
+{
+zlibVersion ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_zlibVersion="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_zlibVersion" = no; then
+ for ac_lib in z; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char zlibVersion ();
+int
+main ()
+{
+zlibVersion ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_zlibVersion="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_zlibVersion" >&5
+echo "${ECHO_T}$ac_cv_search_zlibVersion" >&6
+if test "$ac_cv_search_zlibVersion" != no; then
+ test "$ac_cv_search_zlibVersion" = "none required" || LIBS="$ac_cv_search_zlibVersion $LIBS"
+
+for ac_header in zlib.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+fi
+
+
# For the TUI, we need enhanced curses functionality.
#
# FIXME: kettenis/20040905: We prefer ncurses over the vendor-supplied
--- gdb/configure.ac 2008-03-25 15:53:56.000000000 -0700
+++ gdb/configure.ac 2008-03-24 15:50:25.000000000 -0700
@@ -394,6 +394,9 @@
# Some systems (e.g. Solaris) have `socketpair' in libsocket.
AC_SEARCH_LIBS(socketpair, socket)
+# Link in zlib if we can. This allows us to read compressed debug sections.
+AC_SEARCH_LIBS(zlibVersion, z, [AC_CHECK_HEADERS(zlib.h)])
+
# For the TUI, we need enhanced curses functionality.
#
# FIXME: kettenis/20040905: We prefer ncurses over the vendor-supplied
--- gdb/dwarf2read.c 2008-03-25 15:53:56.000000000 -0700
+++ gdb/dwarf2read.c 2008-03-24 17:28:44.000000000 -0700
@@ -50,6 +50,9 @@
#include "gdb_string.h"
#include "gdb_assert.h"
#include <sys/types.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
/* A note on memory usage for this file.
@@ -195,6 +198,10 @@
/* names of the debugging sections */
+/* Note that if the debugging section has been compressed, it might
+ have a name like .debug_info.zlib.nnnn (where nnn is the
+ uncompressed size). */
+
#define INFO_SECTION ".debug_info"
#define ABBREV_SECTION ".debug_abbrev"
#define LINE_SECTION ".debug_line"
@@ -1109,6 +1116,40 @@
return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL);
}
+/* Given a section name like .debug_str.zlib.nnnn, where nnnn is the
+ uncompressed section size, returns nnnn as an unsigned int. For
+ other sections, returns the size as per bfd_get_section_size. */
+static unsigned int
+uncompressed_section_size (asection *sectp)
+{
+ unsigned int uncompressed_size = 0;
+ char *compression_type = strchr (sectp->name + 1, '.');
+ if (compression_type != NULL)
+ {
+ char *size_string = strchr (compression_type + 1, '.');
+ char *strtol_error;
+ if (size_string != NULL
+ && size_string[1] != '\0')
+ uncompressed_size = strtoul (size_string + 1, &strtol_error, 10);
+ if (uncompressed_size > 0 && *strtol_error == '\0')
+ return uncompressed_size;
+ }
+ return bfd_get_section_size (sectp);
+}
+
+/* When loading sections, we can either look for the section name,
+ * or for section_name.zlib.nnnn, which indicates a compressed
+ * section. nnnn is the uncompressed section size. */
+
+static int
+section_is_p(asection *sectp, const char *name)
+{
+ int name_size = strlen (name);
+ return (strcmp (sectp->name, name) == 0
+ || (strncmp (sectp->name, name, name_size) == 0
+ && sectp->name[name_size] == '.'));
+}
+
/* This function is mapped across the sections and remembers the
offset and size of each of the debugging sections we are interested
in. */
@@ -1116,63 +1157,63 @@
static void
dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr)
{
- if (strcmp (sectp->name, INFO_SECTION) == 0)
+ if (section_is_p (sectp, INFO_SECTION))
{
- dwarf2_per_objfile->info_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->info_size = uncompressed_section_size (sectp);
dwarf_info_section = sectp;
}
- else if (strcmp (sectp->name, ABBREV_SECTION) == 0)
+ else if (section_is_p (sectp, ABBREV_SECTION))
{
- dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->abbrev_size = uncompressed_section_size (sectp);
dwarf_abbrev_section = sectp;
}
- else if (strcmp (sectp->name, LINE_SECTION) == 0)
+ else if (section_is_p (sectp, LINE_SECTION))
{
- dwarf2_per_objfile->line_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->line_size = uncompressed_section_size (sectp);
dwarf_line_section = sectp;
}
- else if (strcmp (sectp->name, PUBNAMES_SECTION) == 0)
+ else if (section_is_p (sectp, PUBNAMES_SECTION))
{
- dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->pubnames_size = uncompressed_section_size (sectp);
dwarf_pubnames_section = sectp;
}
- else if (strcmp (sectp->name, ARANGES_SECTION) == 0)
+ else if (section_is_p (sectp, ARANGES_SECTION))
{
- dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->aranges_size = uncompressed_section_size (sectp);
dwarf_aranges_section = sectp;
}
- else if (strcmp (sectp->name, LOC_SECTION) == 0)
+ else if (section_is_p (sectp, LOC_SECTION))
{
- dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->loc_size = uncompressed_section_size (sectp);
dwarf_loc_section = sectp;
}
- else if (strcmp (sectp->name, MACINFO_SECTION) == 0)
+ else if (section_is_p (sectp, MACINFO_SECTION))
{
- dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->macinfo_size = uncompressed_section_size (sectp);
dwarf_macinfo_section = sectp;
}
- else if (strcmp (sectp->name, STR_SECTION) == 0)
+ else if (section_is_p (sectp, STR_SECTION))
{
- dwarf2_per_objfile->str_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->str_size = uncompressed_section_size (sectp);
dwarf_str_section = sectp;
}
- else if (strcmp (sectp->name, FRAME_SECTION) == 0)
+ else if (section_is_p (sectp, FRAME_SECTION))
{
- dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->frame_size = uncompressed_section_size (sectp);
dwarf_frame_section = sectp;
}
- else if (strcmp (sectp->name, EH_FRAME_SECTION) == 0)
+ else if (section_is_p (sectp, EH_FRAME_SECTION))
{
flagword aflag = bfd_get_section_flags (ignore_abfd, sectp);
if (aflag & SEC_HAS_CONTENTS)
{
- dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->eh_frame_size = uncompressed_section_size (sectp);
dwarf_eh_frame_section = sectp;
}
}
- else if (strcmp (sectp->name, RANGES_SECTION) == 0)
+ else if (section_is_p (sectp, RANGES_SECTION))
{
- dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp);
+ dwarf2_per_objfile->ranges_size = uncompressed_section_size (sectp);
dwarf_ranges_section = sectp;
}
@@ -5234,29 +5275,113 @@
}
/* Read the contents of the section at OFFSET and of size SIZE from the
- object file specified by OBJFILE into the objfile_obstack and return it. */
+ object file specified by OBJFILE into the objfile_obstack and return it.
+ If the section is compressed, uncompress it before returning. */
gdb_byte *
dwarf2_read_section (struct objfile *objfile, asection *sectp)
{
bfd *abfd = objfile->obfd;
- gdb_byte *buf, *retbuf;
bfd_size_type size = bfd_get_section_size (sectp);
+ char *compression_type = NULL;
+ unsigned long uncompressed_size = 0;
if (size == 0)
return NULL;
- buf = obstack_alloc (&objfile->objfile_obstack, size);
- retbuf = symfile_relocate_debug_section (abfd, sectp, buf);
- if (retbuf != NULL)
- return retbuf;
+ /* If the section is stored compressed, it will have the name
+ .debug_*.zlib.nnnn, where nnnn is the uncompressed size. */
+ compression_type = strchr (sectp->name + 1, '.');
+ if (compression_type != NULL)
+ {
+ char *size_string = strchr (compression_type + 1, '.');
+ char *strtol_error;
+ if (size_string != NULL
+ && size_string[1] != '\0')
+ uncompressed_size = strtoul (size_string + 1, &strtol_error, 10);
+ if (uncompressed_size == 0 || *strtol_error != '\0')
+ error (_("Dwarf Error: Can't parse size at end of section name '%s'"
+ " in '%s'"),
+ sectp->name, bfd_get_filename (abfd));
+ }
+
+ /* Handle the case of a normal, not-compressed section. */
+ if (compression_type == NULL)
+ {
+ gdb_byte *buf = obstack_alloc (&objfile->objfile_obstack, size);
+ /* When debugging .o files, we may need to apply relocations; see
+ http://www.cygwin.com/ml/gdb-patches/2002-04/msg00136.html .
+ We never compress sections in .o files, so we only need to
+ try this when the section is not compressed. */
+ gdb_byte *retbuf = symfile_relocate_debug_section (abfd, sectp, buf);
+ if (retbuf != NULL)
+ return retbuf;
+
+ if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
+ || bfd_bread (buf, size, abfd) != size)
+ error (_("Dwarf Error: Can't read DWARF data from '%s'"),
+ bfd_get_filename (abfd));
+
+ return buf;
+ }
+
+ /* Handle the case of a section compressed using zlib. */
+ if (strncmp (compression_type, ".zlib.", sizeof(".zlib.")-1) == 0)
+ {
+#ifndef HAVE_ZLIB_H
+ error (_("Support for compressed DWARF data (from '%s') is disabled "
+ "in this copy of GDB"),
+ bfd_get_filename (abfd));
+#else
+ int rc;
+ gdb_byte *compressed_buffer = xmalloc (size);
+ Bytef *uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack,
+ uncompressed_size);
+ z_stream strm;
+
+ if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
+ || bfd_bread (compressed_buffer, size, abfd) != size)
+ error (_("Dwarf Error: Can't read DWARF data from '%s'"),
+ bfd_get_filename (abfd));
+
+ /* It is possible the section consists of several compressed
+ buffers concatenated together, so we uncompress in a loop. */
+ strm.zalloc = NULL;
+ strm.zfree = NULL;
+ strm.opaque = NULL;
+ strm.next_in = (Bytef*)compressed_buffer;
+ strm.avail_in = size;
+ strm.avail_out = uncompressed_size;
+ rc = inflateInit (&strm);
+ while (strm.avail_in > 0)
+ {
+ if (rc != Z_OK)
+ error (_("Dwarf Error: setting up DWARF uncompression in '%s': %d"),
+ bfd_get_filename (abfd), rc);
+ strm.next_out = (uncompressed_buffer
+ + (uncompressed_size - strm.avail_out));
+ rc = inflate (&strm, Z_FINISH);
+ if (rc != Z_STREAM_END)
+ error (_("Dwarf Error: zlib error uncompressing from '%s': %d"),
+ bfd_get_filename (abfd), rc);
+ rc = inflateReset (&strm);
+ }
+ rc = inflateEnd (&strm);
+ if (rc != Z_OK
+ || strm.avail_out != 0)
+ error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"),
+ bfd_get_filename (abfd), rc);
- if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
- || bfd_bread (buf, size, abfd) != size)
- error (_("Dwarf Error: Can't read DWARF data from '%s'"),
- bfd_get_filename (abfd));
+ xfree (compressed_buffer);
+ return uncompressed_buffer;
+#endif
+ }
- return buf;
+ /* If we get here, we have an unknown compression type. */
+ error (_("Dwarf Error: Unknown compression type in section named '%s'"
+ " from '%s'"),
+ sectp->name, bfd_get_filename (abfd));
+ return NULL;
}
/* In DWARF version 2, the description of the debugging information is
--- /dev/null 1969-12-31 16:00:00.000000000 -0800
+++ gdb/testsuite/gdb.dwarf2/dw2-compressed.S 2008-03-24 15:50:39.000000000 -0700
@@ -0,0 +1,213 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+/* This tests that gdb can read compressed sections. The contents
+ are the same as dw2-basic.S, but the .debug_abbrev section has been
+ comrpessed using zlib. */
+
+/* Dummy function to provide debug information for. */
+
+ .text
+ .globl _start
+_start:
+ .int 0
+.Lbegin_text1:
+ .globl func_cu1
+ .type func_cu1, %function
+func_cu1:
+.Lbegin_func_cu1:
+ .int 0
+.Lend_func_cu1:
+ .size func_cu1, .-func_cu1
+.Lend_text1:
+
+/* Debug information */
+
+ .section .debug_info
+.Lcu1_begin:
+ /* CU header */
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .4byte .Lline1_begin /* DW_AT_stmt_list */
+ .4byte .Lend_text1 /* DW_AT_high_pc */
+ .4byte .Lbegin_text1 /* DW_AT_low_pc */
+ .ascii "file1.txt\0" /* DW_AT_name */
+ .ascii "GNU C 3.3.3\0" /* DW_AT_producer */
+ .byte 1 /* DW_AT_language (C) */
+
+ /* func_cu1 */
+ .uleb128 2 /* Abbrev: DW_TAG_subprogram */
+ .byte 1 /* DW_AT_external */
+ .byte 1 /* DW_AT_decl_file */
+ .byte 2 /* DW_AT_decl_line */
+ .ascii "func_cu1\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .4byte .Lbegin_func_cu1 /* DW_AT_low_pc */
+ .4byte .Lend_func_cu1 /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_frame_base: length */
+ .byte 0x55 /* DW_AT_frame_base: DW_OP_reg5 */
+
+.Ltype_int:
+ .uleb128 3 /* Abbrev: DW_TAG_base_type */
+ .ascii "int\0" /* DW_AT_name */
+ .byte 4 /* DW_AT_byte_size */
+ .byte 5 /* DW_AT_encoding */
+
+ .byte 0 /* End of children of CU */
+
+.Lcu1_end:
+
+/* Line table */
+ .section .debug_line
+.Lline1_begin:
+ .4byte .Lline1_end - .Lline1_start /* Initial length */
+.Lline1_start:
+ .2byte 2 /* Version */
+ .4byte .Lline1_lines - .Lline1_hdr /* header_length */
+.Lline1_hdr:
+ .byte 1 /* Minimum insn length */
+ .byte 1 /* default_is_stmt */
+ .byte 1 /* line_base */
+ .byte 1 /* line_range */
+ .byte 0x10 /* opcode_base */
+
+ /* Standard lengths */
+ .byte 0
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 0
+
+ /* Include directories */
+ .byte 0
+
+ /* File names */
+ .ascii "file1.txt\0"
+ .uleb128 0
+ .uleb128 0
+ .uleb128 0
+
+ .byte 0
+
+.Lline1_lines:
+ .byte 0 /* DW_LNE_set_address */
+ .uleb128 5
+ .byte 2
+ .4byte .Lbegin_func_cu1
+
+ .byte 3 /* DW_LNS_advance_line */
+ .sleb128 3 /* ... to 4 */
+
+ .byte 1 /* DW_LNS_copy */
+
+ .byte 1 /* DW_LNS_copy (second time as an end-of-prologue marker) */
+
+ .byte 0 /* DW_LNE_set_address */
+ .uleb128 5
+ .byte 2
+ .4byte .Lend_func_cu1
+
+ .byte 0 /* DW_LNE_end_of_sequence */
+ .uleb128 1
+ .byte 1
+
+.Lline1_end:
+
+/* Abbrev table -- compressed */
+ .section .debug_abbrev.zlib.51
+.Labbrev1_begin:
+ .byte 0x78
+ .byte 0x5e
+ .byte 0x63
+ .byte 0x14
+ .byte 0x64
+ .byte 0x14
+ .byte 0x60
+ .byte 0x13
+ .byte 0x62
+ .byte 0x14
+ .byte 0x64
+ .byte 0x64
+ .byte 0xe6
+ .byte 0x50
+ .byte 0xe5
+ .byte 0x10
+ .byte 0xe6
+ .byte 0x66
+ .byte 0x60
+ .byte 0x60
+ .byte 0xd2
+ .byte 0x63
+ .byte 0xb0
+ .byte 0xe7
+ .byte 0xb1
+ .byte 0xe2
+ .byte 0xb6
+ .byte 0xe6
+ .byte 0x66
+ .byte 0xe6
+ .byte 0xf0
+ .byte 0x14
+ .byte 0x16
+ .byte 0x64
+ .byte 0x14
+ .byte 0x62
+ .byte 0x74
+ .byte 0xe0
+ .byte 0x02
+ .byte 0x00
+ .byte 0x25
+ .byte 0x78
+ .byte 0x02
+ .byte 0x81
+ .byte 0x78
+ .byte 0x9c
+ .byte 0x63
+ .byte 0x60
+ .byte 0x60
+ .byte 0x56
+ .byte 0x61
+ .byte 0x60
+ .byte 0xe6
+ .byte 0xe0
+ .byte 0xe6
+ .byte 0xb6
+ .byte 0xe3
+ .byte 0x66
+ .byte 0x00
+ .byte 0x02
+ .byte 0x00
+ .byte 0x04
+ .byte 0x9c
+ .byte 0x00
+ .byte 0x92
--- /dev/null 1969-12-31 16:00:00.000000000 -0800
+++ gdb/testsuite/gdb.dwarf2/dw2-compressed.exp 2008-03-24 15:50:39.000000000 -0700
@@ -0,0 +1,52 @@
+# Copyright 2008 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/>.
+
+# Minimal DWARF-2 unit test
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-compressed"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}.x
+
+if { [gdb_compile "${srcdir}/${subdir}/main.c" "main-ndebug.o" object -g0] != "" } {
+ return -1
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${testfile}.o" object {nodebug}] != "" } {
+ return -1
+}
+
+if { [gdb_compile "${testfile}.o main-ndebug.o -static -nostdlib" "${binfile}" executable {debug}] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test "set listsize 1" ""
+gdb_test "list func_cu1" "4\[ \t\]+File 1 Line 4"
+gdb_test "ptype func_cu1" "type = int \\(\\)"