libdwelf: Add dwelf_scn_gnu_compressed_size.
authorMark Wielaard <mjw@redhat.com>
Tue, 17 Nov 2015 22:52:39 +0000 (23:52 +0100)
committerMark Wielaard <mjw@redhat.com>
Wed, 6 Jan 2016 13:27:10 +0000 (14:27 +0100)
Helper function to get the size of a GNU compressed zdebug section.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
14 files changed:
libdw/ChangeLog
libdw/libdw.map
libdwelf/ChangeLog
libdwelf/Makefile.am
libdwelf/dwelf_scn_gnu_compressed_size.c [new file with mode: 0644]
libdwelf/libdwelf.h
tests/ChangeLog
tests/Makefile.am
tests/dwelfgnucompressed.c [new file with mode: 0644]
tests/run-dwelfgnucompressed.sh [new file with mode: 0755]
tests/testfile-zgnu32.bz2 [new file with mode: 0755]
tests/testfile-zgnu32be.bz2 [new file with mode: 0755]
tests/testfile-zgnu64.bz2 [new file with mode: 0755]
tests/testfile-zgnu64be.bz2 [new file with mode: 0755]

index d0e97f3..89d0326 100644 (file)
@@ -1,3 +1,7 @@
+2015-10-28  Mark Wielaard  <mjw@redhat.com>
+
+       * libdw.map (ELFUTILS_0.165): New. Add dwelf_scn_gnu_compressed_size.
+
 2015-12-02  Mark Wielaard  <mjw@redhat.com>
 
        * fde.c (intern_fde): Don't leak duplicate FDEs.
index 1d4cbb0..1681b6b 100644 (file)
@@ -322,3 +322,8 @@ ELFUTILS_0.161 {
     dwarf_macro_getparamcnt;
     dwarf_macro_param;
 } ELFUTILS_0.160;
+
+ELFUTILS_0.165 {
+  global:
+    dwelf_scn_gnu_compressed_size;
+} ELFUTILS_0.161;
index f182ecf..fe8af1b 100644 (file)
@@ -1,3 +1,10 @@
+2015-10-28  Mark Wielaard  <mjw@redhat.com>
+
+       * Makefile.am (libdwelf_a_SOURCES): Add
+       dwelf_scn_gnu_compressed_size.c.
+       * dwelf_scn_gnu_compressed_size.c: Likewise.
+       * libdwelf.h (dwelf_scn_gnu_compressed_size): New declaration.
+
 2015-10-14  Chih-Hung Hsieh  <chh@google.com>
 
        * dwelf_elf_gnu_build_id.c (find_elf_build_id): Move nested function
index cd4b7dd..4de4b2e 100644 (file)
@@ -2,7 +2,7 @@
 ##
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2014 Red Hat, Inc.
+## Copyright (C) 2014, 2015 Red Hat, Inc.
 ## This file is part of elfutils.
 ##
 ## This file is free software; you can redistribute it and/or modify
@@ -40,7 +40,7 @@ pkginclude_HEADERS = libdwelf.h
 noinst_HEADERS = libdwelfP.h
 
 libdwelf_a_SOURCES = dwelf_elf_gnu_debuglink.c dwelf_dwarf_gnu_debugaltlink.c \
-       dwelf_elf_gnu_build_id.c
+                    dwelf_elf_gnu_build_id.c dwelf_scn_gnu_compressed_size.c
 
 libdwelf = $(libdw)
 
diff --git a/libdwelf/dwelf_scn_gnu_compressed_size.c b/libdwelf/dwelf_scn_gnu_compressed_size.c
new file mode 100644 (file)
index 0000000..d39b702
--- /dev/null
@@ -0,0 +1,77 @@
+/* Return size of GNU compressed section.
+   Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils 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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwelfP.h"
+#include "libelfP.h"
+
+ssize_t
+dwelf_scn_gnu_compressed_size (Elf_Scn *scn)
+{
+  if (scn == NULL)
+    return -1;
+
+  GElf_Shdr shdr;
+  if (gelf_getshdr (scn, &shdr) == NULL)
+    return -1;
+
+  /* Allocated or no bits sections can never be compressed.  */
+  if ((shdr.sh_flags & SHF_ALLOC) != 0
+      || shdr.sh_type == SHT_NULL
+      || shdr.sh_type == SHT_NOBITS)
+    return -1;
+
+  Elf_Data *d = elf_rawdata (scn, NULL);
+  if (d == NULL)
+    return -1;
+
+  if (d->d_size >= 4 + 8
+      && memcmp (d->d_buf, "ZLIB", 4) == 0)
+    {
+      /* There is a 12-byte header of "ZLIB" followed by
+        an 8-byte big-endian size.  There is only one type and
+        alignment isn't preserved separately.  */
+      uint64_t size;
+      memcpy (&size, d->d_buf + 4, sizeof size);
+      size = be64toh (size);
+
+      /* One more sanity check, size should be bigger than original
+        data size plus some overhead (4 chars ZLIB + 8 bytes size + 6
+        bytes zlib stream overhead + 5 bytes overhead max for one 16K
+        block) and should fit into a size_t.  */
+      if (size + 4 + 8 + 6 + 5 < d->d_size || size > SIZE_MAX)
+       return -1;
+
+      return size;
+    }
+
+  return -1;
+}
index e16dc0f..7f7f679 100644 (file)
@@ -1,5 +1,5 @@
 /* Interfaces for libdwelf. DWARF ELF Low-level Functions.
-   Copyright (C) 2014 Red Hat, Inc.
+   Copyright (C) 2014, 2015 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -65,6 +65,13 @@ extern ssize_t dwelf_dwarf_gnu_debugaltlink (Dwarf *dwarf,
    note.  Returns -1 in case of malformed data or other errors.  */
 extern ssize_t dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp);
 
+/* Returns the size of the uncompressed data of a GNU compressed
+   section.  The section name should start with .zdebug (but this
+   isn't checked by this function).  If the section isn't compressed
+   (the section data doesn't start with ZLIB) -1 is returned. If an
+   error occured -1 is returned and elf_errno is set.  */
+extern ssize_t dwelf_scn_gnu_compressed_size (Elf_Scn *scn);
+
 #ifdef __cplusplus
 }
 #endif
index 933f7c9..5afe4bd 100644 (file)
@@ -1,3 +1,15 @@
+2015-10-28  Mark Wielaard  <mjw@redhat.com>
+
+       * dwelfgnucompressed.c: New file.
+       * run-dwelfgnucompressed.sh: New test.
+       * testfile-zgnu32.bz2: New testfile.
+       * testfile-zgnu64.bz2: Likewise.
+       * Makefile.am (check_PROGRAMS): Add dwelfgnucompressed.
+       (TESTS): Add run-dwelfgnucompressed.sh.
+       (EXTRA_DIST): Add run-dwelfgnucompressed.sh, testfile-zgnu32.bz2,
+       testfile-zgnu64.bz2, testfile-zgnu32be.bz2, testfile-zgnu64be.bz2.
+       (dwelfgnucompressed_LDADD): New variable.
+
 2015-12-31  Mark Wielaard  <mjw@redhat.com>
 
        * elfstrmerge.c (main): Warn about STT_SECTION symbol for shstrhndx.
index 54d88f2..8e2f283 100644 (file)
@@ -52,7 +52,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  backtrace-data backtrace-dwarf debuglink debugaltlink \
                  buildid deleted deleted-lib.so aggregate_size vdsosyms \
                  getsrc_die strptr newdata elfstrtab dwfl-proc-attach \
-                 elfshphehdr elfstrmerge
+                 elfshphehdr elfstrmerge dwelfgnucompressed
 
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
            asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -120,7 +120,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \
        run-linkmap-cut.sh run-aggregate-size.sh vdsosyms run-readelf-A.sh \
        run-getsrc-die.sh run-strptr.sh newdata elfstrtab dwfl-proc-attach \
-       elfshphehdr run-lfs-symbols.sh
+       elfshphehdr run-lfs-symbols.sh run-dwelfgnucompressed.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -306,7 +306,10 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile-x32-core.bz2 testfile-x32.bz2 \
             backtrace.x32.core.bz2 backtrace.x32.exec.bz2 \
             testfile-x32-s.bz2 testfile-x32-d.bz2 testfile-x32-debug.bz2 \
-            run-lfs-symbols.sh lfs-symbols testfile-nolfs.bz2
+            run-lfs-symbols.sh lfs-symbols testfile-nolfs.bz2 \
+            testfile-zgnu32.bz2 testfile-zgnu64.bz2 \
+            testfile-zgnu32be.bz2 testfile-zgnu64be.bz2 \
+            run-dwelfgnucompressed.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1'
@@ -455,6 +458,7 @@ dwfl_proc_attach_LDADD = $(libdw)
 dwfl_proc_attach_LDFLAGS = -pthread $(AM_LDFLAGS)
 elfshphehdr_LDADD =$(libelf)
 elfstrmerge_LDADD = $(libebl) $(libelf)
+dwelfgnucompressed_LDADD = $(libelf) $(libdw)
 
 if GCOV
 check: check-am coverage
diff --git a/tests/dwelfgnucompressed.c b/tests/dwelfgnucompressed.c
new file mode 100644 (file)
index 0000000..0132271
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file 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.
+
+   elfutils 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include ELFUTILS_HEADER(elf)
+#include ELFUTILS_HEADER(dwelf)
+#include <gelf.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+  int result = 0;
+  int cnt;
+
+  elf_version (EV_CURRENT);
+
+  for (cnt = 1; cnt < argc; ++cnt)
+    {
+      int fd = open (argv[cnt], O_RDONLY);
+
+      Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
+      if (elf == NULL)
+       {
+         printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1));
+         result = 1;
+         close (fd);
+         continue;
+       }
+
+      size_t shdrstrndx;
+      if (elf_getshdrstrndx (elf, &shdrstrndx) == -1)
+       {
+         printf ("elf_getshdrstrnd failed %s\n", elf_errmsg (-1));
+         result = 1;
+         close (fd);
+         continue;
+       }
+
+      Elf_Scn *scn = NULL;
+      while ((scn = elf_nextscn (elf, scn)) != NULL)
+       {
+         int idx = elf_ndxscn (scn);
+         GElf_Shdr shdr;
+         if (gelf_getshdr (scn, &shdr) == NULL)
+           {
+             printf ("gelf_getshdr failed: %s\n", elf_errmsg (-1));
+             result = 1;
+             break;
+           }
+
+         const char *sname = elf_strptr (elf, shdrstrndx, shdr.sh_name);
+         if (sname == NULL)
+           {
+             printf ("couldn't get section name: %s\n", elf_errmsg (-1));
+             result = 1;
+             break;
+           }
+
+         if (strncmp(".zdebug", sname, strlen (".zdebug")) == 0)
+           {
+             ssize_t size;
+             if ((size = dwelf_scn_gnu_compressed_size (scn)) == -1)
+               {
+                 printf ("dwelf_scn_gnu_compressed_size failed: %s\n",
+                         elf_errmsg (-1));
+                 result = 1;
+                 break;
+               }
+             printf ("section %d: GNU Compressed size: %zx\n", idx, size);
+           }
+       }
+
+      elf_end (elf);
+      close (fd);
+    }
+
+  return result;
+}
diff --git a/tests/run-dwelfgnucompressed.sh b/tests/run-dwelfgnucompressed.sh
new file mode 100755 (executable)
index 0000000..b93a56f
--- /dev/null
@@ -0,0 +1,108 @@
+#! /bin/sh
+# Copyright (C) 2015 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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/>.
+
+. $srcdir/test-subr.sh
+
+# = funcs.s =
+# .globl testfunc
+# testfunc:
+#      nop
+#      ret
+# .type testfunc, @function
+# .size testfunc, .-testfunc
+#
+# .globl testfunc2
+# testfunc2:
+#      call testfunc
+#      nop
+#      nop
+#      ret
+# .type testfunc2, @function
+# .size testfunc2, .-testfunc2
+#
+# .globl functest3
+# functest3:
+#      jmp local
+#      nop
+#      nop
+# local:
+#      call testfunc2
+#      ret
+# .type functest3, @function
+# .size functest3, .-functest3
+
+# = start.s =
+# .global _start
+# _start:
+#      call functest3
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      nop
+#      ret
+# .type _start, @function
+# .size _start, .-_start
+
+# gas --compress-debug-sections=zlib-gnu -32 -g -o start.o start.s
+# gas --compress-debug-sections=zlib-gnu -32 -g -o funcs.o funcs.s
+# ld --compress-debug-sections=zlib-gnu -melf_i386 -g -o zgnu32 funcs.o start.o
+
+# gas --compress-debug-sections=zlib-gnu -64 -g -o start.o start.s
+# gas --compress-debug-sections=zlib-gnu -64 -g -o funcs.o funcs.s
+# ld --compress-debug-sections=zlib-gnu -g -o zgnu32 funcs.o start.o
+
+testfiles testfile-zgnu64
+testrun_compare ${abs_top_builddir}/tests/dwelfgnucompressed testfile-zgnu64 <<\EOF
+section 2: GNU Compressed size: 60
+section 3: GNU Compressed size: aa
+section 5: GNU Compressed size: 8d
+EOF
+
+testfiles testfile-zgnu64be
+testrun_compare ${abs_top_builddir}/tests/dwelfgnucompressed testfile-zgnu64be <<\EOF
+section 3: GNU Compressed size: 60
+section 4: GNU Compressed size: 7e
+section 6: GNU Compressed size: 8d
+EOF
+
+testfiles testfile-zgnu32
+testrun_compare ${abs_top_builddir}/tests/dwelfgnucompressed testfile-zgnu32 <<\EOF
+section 2: GNU Compressed size: 40
+section 3: GNU Compressed size: 9a
+section 5: GNU Compressed size: 85
+EOF
+
+testfiles testfile-zgnu32be
+testrun_compare ${abs_top_builddir}/tests/dwelfgnucompressed testfile-zgnu32be <<\EOF
+section 3: GNU Compressed size: 40
+section 4: GNU Compressed size: 6e
+section 6: GNU Compressed size: 85
+EOF
+
+exit 0
diff --git a/tests/testfile-zgnu32.bz2 b/tests/testfile-zgnu32.bz2
new file mode 100755 (executable)
index 0000000..9d622ca
Binary files /dev/null and b/tests/testfile-zgnu32.bz2 differ
diff --git a/tests/testfile-zgnu32be.bz2 b/tests/testfile-zgnu32be.bz2
new file mode 100755 (executable)
index 0000000..c1dd589
Binary files /dev/null and b/tests/testfile-zgnu32be.bz2 differ
diff --git a/tests/testfile-zgnu64.bz2 b/tests/testfile-zgnu64.bz2
new file mode 100755 (executable)
index 0000000..1bc2c09
Binary files /dev/null and b/tests/testfile-zgnu64.bz2 differ
diff --git a/tests/testfile-zgnu64be.bz2 b/tests/testfile-zgnu64be.bz2
new file mode 100755 (executable)
index 0000000..390c9c9
Binary files /dev/null and b/tests/testfile-zgnu64be.bz2 differ