[PATCHv2] strip: keep .ctf section in stripped file

Message ID 20220601155527.2192182-1-guillermo.e.martinez@oracle.com
State Dropped
Headers
Series [PATCHv2] strip: keep .ctf section in stripped file |

Commit Message

Guillermo E. Martinez June 1, 2022, 3:55 p.m. UTC
  Hello,

This is the second version patch to avoid remove the CTF section in
stripped files. Changes from v1:

  - Add description in tests/run-strip-remove-keep-ctf.sh
    mentioning how to regenerate test input file (testfile-ctf)

Please let me know your thoughts.

Kind regard,
guillermo

CTF debug format was designed to be present in stripped files, so
this section should not be removed, so a new --remove-ctf option
is added to indicate explicitly that .ctf section will be stripped
out from binary file.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
---
 ChangeLog                          |  23 ++++
 libebl/eblsectionstripp.c          |   4 +-
 libebl/libebl.h                    |   2 +-
 libelf/elf-knowledge.h             |   7 +-
 libelf/elf32_checksum.c            |   2 +-
 src/elfcmp.c                       |   4 +-
 src/strip.c                        |  71 ++++++++--
 tests/Makefile.am                  |   6 +-
 tests/run-strip-remove-keep-ctf.sh | 212 +++++++++++++++++++++++++++++
 tests/testfile-ctf.bz2             | Bin 0 -> 2620 bytes
 10 files changed, 309 insertions(+), 22 deletions(-)
 create mode 100755 tests/run-strip-remove-keep-ctf.sh
 create mode 100755 tests/testfile-ctf.bz2

GIT binary patch
literal 2620
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

literal 0
HcmV?d00001


base-commit: b8713b3fd0617415c76df8c9da70f8e2f26d3134
  

Comments

Mark Wielaard Dec. 20, 2022, 9:35 p.m. UTC | #1
Hi Guillermo,

On Wed, Jun 01, 2022 at 10:55:27AM -0500, Guillermo E. Martinez via Elfutils-devel wrote:
> This is the second version patch to avoid remove the CTF section in
> stripped files. Changes from v1:
> 
>   - Add description in tests/run-strip-remove-keep-ctf.sh
>     mentioning how to regenerate test input file (testfile-ctf)
> 
> Please let me know your thoughts.
>
> [...]
> 
> CTF debug format was designed to be present in stripped files, so
> this section should not be removed, so a new --remove-ctf option
> is added to indicate explicitly that .ctf section will be stripped
> out from binary file.

Sorry, I see I never reviewed this v2 variant.  I know we tried to
coordinate with binutils so eu-strip and binutils strip would do the
same thing. And that Jose had an idea for a new section flag to
automatically detect what section should/shouldn't be stripped (into a
separate .debug file). What was the conclusion of that?

Thanks,

Mark
  
Mark Wielaard Feb. 22, 2023, 4:42 p.m. UTC | #2
Hi,

On Tue, 2022-12-20 at 22:35 +0100, Mark Wielaard wrote:
> On Wed, Jun 01, 2022 at 10:55:27AM -0500, Guillermo E. Martinez via Elfutils-devel wrote:
> > This is the second version patch to avoid remove the CTF section in
> > stripped files. Changes from v1:
> > 
> >   - Add description in tests/run-strip-remove-keep-ctf.sh
> >     mentioning how to regenerate test input file (testfile-ctf)
> > 
> > Please let me know your thoughts.
> > 
> > [...]
> > 
> > CTF debug format was designed to be present in stripped files, so
> > this section should not be removed, so a new --remove-ctf option
> > is added to indicate explicitly that .ctf section will be stripped
> > out from binary file.
> 
> Sorry, I see I never reviewed this v2 variant.  I know we tried to
> coordinate with binutils so eu-strip and binutils strip would do the
> same thing. And that Jose had an idea for a new section flag to
> automatically detect what section should/shouldn't be stripped (into a
> separate .debug file). What was the conclusion of that?

Any update on this?
How should .ctf sections be dealt with by strip like tools?

Thanks,

Mark
  
Jose E. Marchesi Feb. 22, 2023, 4:59 p.m. UTC | #3
> Hi,
>
> On Tue, 2022-12-20 at 22:35 +0100, Mark Wielaard wrote:
>> On Wed, Jun 01, 2022 at 10:55:27AM -0500, Guillermo E. Martinez via Elfutils-devel wrote:
>> > This is the second version patch to avoid remove the CTF section in
>> > stripped files. Changes from v1:
>> > 
>> >   - Add description in tests/run-strip-remove-keep-ctf.sh
>> >     mentioning how to regenerate test input file (testfile-ctf)
>> > 
>> > Please let me know your thoughts.
>> > 
>> > [...]
>> > 
>> > CTF debug format was designed to be present in stripped files, so
>> > this section should not be removed, so a new --remove-ctf option
>> > is added to indicate explicitly that .ctf section will be stripped
>> > out from binary file.
>> 
>> Sorry, I see I never reviewed this v2 variant.  I know we tried to
>> coordinate with binutils so eu-strip and binutils strip would do the
>> same thing. And that Jose had an idea for a new section flag to
>> automatically detect what section should/shouldn't be stripped (into a
>> separate .debug file). What was the conclusion of that?
>
> Any update on this?
> How should .ctf sections be dealt with by strip like tools?

I think the conclusion was that having a NOSTRIP flag in the object file
is far from trivial, because what "strip" means for several people and
tools is not clear.

So I guess we are stuck with the old keep-a-list method.

Or we may add NOSTRIP meaning "_never ever_ strip this section, period,
no matter what."
  
Guillermo E. Martinez Feb. 22, 2023, 5:12 p.m. UTC | #4
On Wed, Feb 22, 2023 at 05:42:45PM +0100, Mark Wielaard wrote:
> Hi,
> 

Hi Mark,

> On Tue, 2022-12-20 at 22:35 +0100, Mark Wielaard wrote:
> > On Wed, Jun 01, 2022 at 10:55:27AM -0500, Guillermo E. Martinez via Elfutils-devel wrote:
> > > This is the second version patch to avoid remove the CTF section in
> > > stripped files. Changes from v1:
> > > 
> > >   - Add description in tests/run-strip-remove-keep-ctf.sh
> > >     mentioning how to regenerate test input file (testfile-ctf)
> > > 
> > > Please let me know your thoughts.
> > > 
> > > [...]
> > > 
> > > CTF debug format was designed to be present in stripped files, so
> > > this section should not be removed, so a new --remove-ctf option
> > > is added to indicate explicitly that .ctf section will be stripped
> > > out from binary file.
> > 
> > Sorry, I see I never reviewed this v2 variant.  I know we tried to
> > coordinate with binutils so eu-strip and binutils strip would do the
> > same thing. And that Jose had an idea for a new section flag to
> > automatically detect what section should/shouldn't be stripped (into a
> > separate .debug file). What was the conclusion of that?
> 
> Any update on this?
> How should .ctf sections be dealt with by strip like tools?
> 

Sorry for late reply,

The conclusion was basically not use section flags to identify which
section should be stripped out or not, so, it requires other mechanisms
for explicitly specifying which sections should be removed, as eu-strip
does using arguments.

https://sourceware.org/bugzilla/show_bug.cgi?id=29737

Worth it mention here, that my last test shows that .ctf section is not
stripped by ue-strip because it doesn't have a "debug" section name. 

Thanks,
guillermo
  
Mark Wielaard Feb. 22, 2023, 11:04 p.m. UTC | #5
Hi,

On Wed, Feb 22, 2023 at 11:12:07AM -0600, Guillermo E. Martinez wrote:
> The conclusion was basically not use section flags to identify which
> section should be stripped out or not, so, it requires other mechanisms
> for explicitly specifying which sections should be removed, as eu-strip
> does using arguments.
> 
> https://sourceware.org/bugzilla/show_bug.cgi?id=29737

OK, thanks.

> Worth it mention here, that my last test shows that .ctf section is not
> stripped by ue-strip because it doesn't have a "debug" section name. 

Are you sure that is what happens? It might depend on whether or not
you give eu-strip -g or not.

With -g only debug symbols and .debug sections are removed, but it
keeps any other unused/unallocated symbol/section. Without -g I would
expect eu-strip to remove the .ctf section (unless it is an allocated
section or referenced from an allocated section/symbol table).

Cheers,

Mark
  
Guillermo E. Martinez Feb. 23, 2023, 6:34 p.m. UTC | #6
On Thu, Feb 23, 2023 at 12:04:47AM +0100, Mark Wielaard wrote:
> Hi,

Hi Mark,

> 
> On Wed, Feb 22, 2023 at 11:12:07AM -0600, Guillermo E. Martinez wrote:
> > The conclusion was basically not use section flags to identify which
> > section should be stripped out or not, so, it requires other mechanisms
> > for explicitly specifying which sections should be removed, as eu-strip
> > does using arguments.
> > 
> > https://sourceware.org/bugzilla/show_bug.cgi?id=29737
> 
> OK, thanks.
> 
> > Worth it mention here, that my last test shows that .ctf section is not
> > stripped by ue-strip because it doesn't have a "debug" section name. 
> 
> Are you sure that is what happens? It might depend on whether or not
> you give eu-strip -g or not.
> 

Oh, sorry. Yes, you are right!. I looked what was wrong with my test
environment and I didn't realize the use of `-g' option  in my
find-debuginfo script.

> With -g only debug symbols and .debug sections are removed, but it
> keeps any other unused/unallocated symbol/section. Without -g I would
> expect eu-strip to remove the .ctf section (unless it is an allocated
> section or referenced from an allocated section/symbol table).
> 

I see, thanks for explanation!.

I'll send immediately PATCH-v3 rebased from master.

Kind regards,
guillermo
  

Patch

diff --git a/ChangeLog b/ChangeLog
index f1a14b5c..2b608866 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@ 
+2022-05-21  Guillermo E. Martinez  <guillermo.e.martinez@oracle.com>
+
+	* libebl/eblsectionstripp.c (ebl_section_strip_p): Use
+	remove_ctf argument.
+	(SECTION_STRIP_P): Likewise.
+	* libebl/libebl.h (ebl_section_strip_p): Likewise.
+	* libelf/elf-knowledge.h (SECTION_STRIP_P): Update macro
+	definition to use remove_ctf to determine whether .ctf
+	section is stripped out.
+	* libelf/elf32_checksum.c (elfw2): Use false value for
+	remove_ctf parameter.
+	* src/elfcmp.c (main): Likewise.
+	* src/strip.c (options): Add --remove-ctf option set by
+	remove_ctf variable.
+	(set_remove_special_section_opt): Add new function.
+	(erratic_special_section_opt): Likewise.
+	(parse_opt): Parse new --remove-ctf option.
+	(handle_elf): Adjust .comment and use remove_ctf argument.
+	* tests/Makefile.am (TEST): Add run-strip-remove-keep-ctf.sh
+	and testfile-ctf.bz2.
+	* tests/run-strip-remove-keep-ctf.sh: Add new testcase.
+	* tests/testfile-ctf.bz2: Add new test harness.
+
 2022-05-02  Mark Wielaard  <mark@klomp.org>
 
 	* Makefile.am (AM_DISTCHECK_CONFIGURE_FLAGS): Remove
diff --git a/libebl/eblsectionstripp.c b/libebl/eblsectionstripp.c
index a5624ffe..f26cc170 100644
--- a/libebl/eblsectionstripp.c
+++ b/libebl/eblsectionstripp.c
@@ -37,7 +37,7 @@ 
 bool
 ebl_section_strip_p (Ebl *ebl, const GElf_Shdr *shdr,
 		     const char *name, bool remove_comment,
-		     bool only_remove_debug)
+		     bool only_remove_debug, bool remove_ctf)
 {
   /* If only debug information should be removed check the name.  There
      is unfortunately no other way.  */
@@ -66,5 +66,5 @@  ebl_section_strip_p (Ebl *ebl, const GElf_Shdr *shdr,
       return false;
     }
 
-  return SECTION_STRIP_P (shdr, name, remove_comment);
+  return SECTION_STRIP_P (shdr, name, remove_comment, remove_ctf);
 }
diff --git a/libebl/libebl.h b/libebl/libebl.h
index 731001d3..067b769e 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -205,7 +205,7 @@  extern bool ebl_relative_reloc_p (Ebl *ebl, int reloc);
 /* Check whether section should be stripped.  */
 extern bool ebl_section_strip_p (Ebl *ebl,
 				 const GElf_Shdr *shdr, const char *name,
-				 bool remove_comment, bool only_remove_debug);
+				 bool remove_comment, bool only_remove_debug, bool remove_ctf);
 
 /* Check if backend uses a bss PLT in this file.  */
 extern bool ebl_bss_plt_p (Ebl *ebl);
diff --git a/libelf/elf-knowledge.h b/libelf/elf-knowledge.h
index 6e005fa5..903a0f4f 100644
--- a/libelf/elf-knowledge.h
+++ b/libelf/elf-knowledge.h
@@ -34,7 +34,7 @@ 
 
 
 /* Test whether a section can be stripped or not.  */
-#define SECTION_STRIP_P(shdr, name, remove_comment) \
+#define SECTION_STRIP_P(shdr, name, remove_comment, remove_ctf) \
   /* Sections which are allocated are not removed.  */			      \
   (((shdr)->sh_flags & SHF_ALLOC) == 0					      \
    /* We never remove .note sections.  */				      \
@@ -45,7 +45,10 @@ 
 	   && strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) != 0\
 	   /* We remove .comment sections only if explicitly told to do so. */\
 	   && (remove_comment						      \
-	       || strcmp (name, ".comment") != 0))))
+	       || strcmp (name, ".comment") != 0)  \
+	   /* We remove .ctf sections only if explicitly told to do so. */\
+	   && (remove_ctf						      \
+	       || strcmp (name, ".ctf") != 0))))
 
 
 /* Test whether `sh_info' field in section header contains a section
diff --git a/libelf/elf32_checksum.c b/libelf/elf32_checksum.c
index c5f27bbe..190bad7d 100644
--- a/libelf/elf32_checksum.c
+++ b/libelf/elf32_checksum.c
@@ -105,7 +105,7 @@  elfw2(LIBELFBITS,checksum) (Elf *elf)
 
       if (SECTION_STRIP_P (shdr,
 			   INTUSE(elf_strptr) (elf, shstrndx, shdr->sh_name),
-			   true))
+			   true, false))
 	/* The section can be stripped.  Don't use it.  */
 	continue;
 
diff --git a/src/elfcmp.c b/src/elfcmp.c
index 21d8d9dc..76f15735 100644
--- a/src/elfcmp.c
+++ b/src/elfcmp.c
@@ -270,7 +270,7 @@  main (int argc, char *argv[])
 	    sname1 = elf_strptr (elf1, shstrndx1, shdr1->sh_name);
 	}
       while (scn1 != NULL && shdr1 != NULL
-	     && ebl_section_strip_p (ebl1, shdr1, sname1, true, false));
+	     && ebl_section_strip_p (ebl1, shdr1, sname1, true, false, false));
 
       GElf_Shdr shdr2_mem;
       GElf_Shdr *shdr2;
@@ -283,7 +283,7 @@  main (int argc, char *argv[])
 	    sname2 = elf_strptr (elf2, shstrndx2, shdr2->sh_name);
 	}
       while (scn2 != NULL && shdr2 != NULL
-	     && ebl_section_strip_p (ebl2, shdr2, sname2, true, false));
+	     && ebl_section_strip_p (ebl2, shdr2, sname2, true, false, false));
 
       if (scn1 == NULL || scn2 == NULL || shdr1 == NULL || shdr2 == NULL)
 	break;
diff --git a/src/strip.c b/src/strip.c
index 452b1279..6f79a1d0 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -62,6 +62,7 @@  ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
 #define OPT_RELOC_DEBUG 	0x103
 #define OPT_KEEP_SECTION 	0x104
 #define OPT_RELOC_DEBUG_ONLY    0x105
+#define OPT_REMOVE_CTF	        0x106
 
 
 /* Definitions of arguments for argp functions.  */
@@ -87,6 +88,8 @@  static const struct argp_option options[] =
     N_("Similar to --reloc-debug-sections, but resolve all trivial relocations between debug sections in place.  No other stripping is performed (operation is not reversible, incompatible with -f, -g, --remove-comment and --remove-section)"), 0 },
   { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
     N_("Remove .comment section"), 0 },
+  { "remove-ctf", OPT_REMOVE_CTF, NULL, 0,
+    N_("Remove .ctf section"), 0 },
   { "remove-section", 'R', "SECTION", 0, N_("Remove the named section.  SECTION is an extended wildcard pattern.  May be given more than once.  Only non-allocated sections can be removed."), 0 },
   { "keep-section", OPT_KEEP_SECTION, "SECTION", 0, N_("Keep the named section.  SECTION is an extended wildcard pattern.  May be given more than once."), 0 },
   { "permissive", OPT_PERMISSIVE, NULL, 0,
@@ -150,6 +153,9 @@  static bool preserve_dates;
 /* If true .comment sections will be removed.  */
 static bool remove_comment;
 
+/* If true .ctf sections will be removed.  */
+static bool remove_ctf;
+
 /* If true remove all debug sections.  */
 static bool remove_debug;
 
@@ -217,6 +223,48 @@  section_name_matches (struct section_pattern *patterns, const char *name)
   return false;
 }
 
+static void
+set_remove_special_section_opt (const char *arg)
+{
+  if (fnmatch (arg, ".comment", FNM_EXTMATCH) == 0)
+    remove_comment = true;
+  else if (fnmatch (arg, ".ctf", FNM_EXTMATCH) == 0)
+    remove_ctf = true;
+}
+
+static error_t
+erratic_special_section_opt (struct argp_state *state)
+{
+  int s;
+  struct {
+    const char *name;
+    bool remove;
+  } special_secs[] = {
+      {
+        .name = ".comment",
+        .remove = remove_comment
+      },
+      {
+        .name = ".ctf",
+        .remove = remove_ctf
+      },
+      {
+        .name = NULL,
+      }
+  };
+
+  for (s = 0; special_secs[s].name; ++s)
+    if (special_secs[s].remove == true
+        && section_name_matches (keep_secs, special_secs[s].name))
+      {
+        argp_error (state,
+                    _("cannot both keep and remove %s section"),
+                    special_secs[s].name);
+        return EINVAL;
+      }
+
+  return 0;
+}
 
 int
 main (int argc, char *argv[])
@@ -325,9 +373,12 @@  parse_opt (int key, char *arg, struct argp_state *state)
       remove_comment = true;
       break;
 
+    case OPT_REMOVE_CTF:
+      remove_ctf = true;
+      break;
+
     case 'R':
-      if (fnmatch (arg, ".comment", FNM_EXTMATCH) == 0)
-	remove_comment = true;
+      set_remove_special_section_opt (arg);
       add_pattern (&remove_secs, arg);
       break;
 
@@ -353,13 +404,8 @@  parse_opt (int key, char *arg, struct argp_state *state)
       break;
 
     case ARGP_KEY_SUCCESS:
-      if (remove_comment == true
-	  && section_name_matches (keep_secs, ".comment"))
-	{
-	  argp_error (state,
-		      _("cannot both keep and remove .comment section"));
-	  return EINVAL;
-	}
+      if (erratic_special_section_opt (state))
+        return EINVAL;
       break;
 
     default:
@@ -1358,7 +1404,7 @@  handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
      all sections which are not used at runtime are stripped out.  But
      there are a few exceptions:
 
-     - special sections named ".comment" and ".note" are kept
+     - special sections named ".comment", ".note" and ".ctf" are kept
      - OS or architecture specific sections are kept since we might not
        know how to handle them
      - if a section is referred to from a section which is not removed
@@ -1371,7 +1417,7 @@  handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
     if (remove_shdrs ? !(shdr_info[cnt].shdr.sh_flags & SHF_ALLOC)
 	: (ebl_section_strip_p (ebl, &shdr_info[cnt].shdr,
 				shdr_info[cnt].name, remove_comment,
-				remove_debug)
+				remove_debug, remove_ctf)
 	   || cnt == shstrndx
 	   || section_name_matches (remove_secs, shdr_info[cnt].name)))
       {
@@ -1534,7 +1580,8 @@  handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 						    &shdr_info[scnidx].shdr,
 						    shdr_info[scnidx].name,
 						    remove_comment,
-						    remove_debug)
+						    remove_debug,
+						    remove_ctf)
 			       && ebl_data_marker_symbol (ebl, sym,
 					elf_strptr (elf,
 						    shdr_info[cnt].shdr.sh_link,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 84c3950a..f30d958e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -197,7 +197,8 @@  TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	msg_tst system-elf-libelf-test \
 	$(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \
 	run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \
-	run-readelf-dw-form-indirect.sh run-strip-largealign.sh
+	run-readelf-dw-form-indirect.sh run-strip-largealign.sh \
+	run-strip-remove-keep-ctf.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -580,7 +581,8 @@  EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     run-readelf-dw-form-indirect.sh testfile-dw-form-indirect.bz2 \
 	     run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \
 	     testfile_nvidia_linemap.bz2 \
-	     testfile-largealign.o.bz2 run-strip-largealign.sh
+	     testfile-largealign.o.bz2 run-strip-largealign.sh \
+	     testfile-ctf.bz2 run-strip-remove-keep-ctf.sh
 
 
 if USE_VALGRIND
diff --git a/tests/run-strip-remove-keep-ctf.sh b/tests/run-strip-remove-keep-ctf.sh
new file mode 100755
index 00000000..9a4fde72
--- /dev/null
+++ b/tests/run-strip-remove-keep-ctf.sh
@@ -0,0 +1,212 @@ 
+#! /bin/sh
+# Copyright (C) 2022 Oracle, 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
+
+# - testfile-ctf.c
+# int
+# main ()
+# {
+#   return 0;
+# }
+#
+# gcc -gctf -g -o testfile-ctf testfile-ctf.c
+# eu-strip testfile-ctf
+
+# strip -o output and -f debug files
+tempfiles testfile.elf testfile.debug
+
+# A random 32bit testfile
+testfiles testfile-ctf
+
+# strip should keep .ctf section
+echo strip testfile-ctf
+testrun ${abs_top_builddir}/src/strip -o testfile.elf -f testfile.debug testfile-ctf
+echo elflint testfile.elf
+testrun ${abs_top_builddir}/src/elflint --gnu testfile.elf
+echo elflint testfile.debug
+testrun ${abs_top_builddir}/src/elflint --gnu -d testfile.debug
+echo readelf testfile.elf
+testrun_compare ${abs_top_builddir}/src/readelf -S testfile.elf <<\EOF
+There are 28 section headers, starting at offset 0x31d8:
+
+Section Headers:
+[Nr] Name                 Type         Addr             Off      Size     ES Flags Lk Inf Al
+[ 0]                      NULL         0000000000000000 00000000 00000000  0        0   0  0
+[ 1] .interp              PROGBITS     0000000000400318 00000318 0000001c  0 A      0   0  1
+[ 2] .note.gnu.property   NOTE         0000000000400338 00000338 00000020  0 A      0   0  8
+[ 3] .note.ABI-tag        NOTE         0000000000400358 00000358 00000020  0 A      0   0  4
+[ 4] .hash                HASH         0000000000400378 00000378 00000018  4 A      6   0  8
+[ 5] .gnu.hash            GNU_HASH     0000000000400390 00000390 0000001c  0 A      6   0  8
+[ 6] .dynsym              DYNSYM       00000000004003b0 000003b0 00000048 24 A      7   1  8
+[ 7] .dynstr              STRTAB       00000000004003f8 000003f8 00000038  0 A      0   0  1
+[ 8] .gnu.version         GNU_versym   0000000000400430 00000430 00000006  2 A      6   0  2
+[ 9] .gnu.version_r       GNU_verneed  0000000000400438 00000438 00000020  0 A      7   1  8
+[10] .rela.dyn            RELA         0000000000400458 00000458 00000030 24 A      6   0  8
+[11] .init                PROGBITS     0000000000401000 00001000 00000017  0 AX     0   0  4
+[12] .text                PROGBITS     0000000000401020 00001020 00000191  0 AX     0   0 16
+[13] .fini                PROGBITS     00000000004011b4 000011b4 00000009  0 AX     0   0  4
+[14] .rodata              PROGBITS     0000000000402000 00002000 00000004  4 AM     0   0  4
+[15] .eh_frame_hdr        PROGBITS     0000000000402004 00002004 00000034  0 A      0   0  4
+[16] .eh_frame            PROGBITS     0000000000402038 00002038 000000d8  0 A      0   0  8
+[17] .init_array          INIT_ARRAY   0000000000403e40 00002e40 00000008  8 WA     0   0  8
+[18] .fini_array          FINI_ARRAY   0000000000403e48 00002e48 00000008  8 WA     0   0  8
+[19] .dynamic             DYNAMIC      0000000000403e50 00002e50 000001a0 16 WA     7   0  8
+[20] .got                 PROGBITS     0000000000403ff0 00002ff0 00000010  8 WA     0   0  8
+[21] .got.plt             PROGBITS     0000000000404000 00003000 00000018  8 WA     0   0  8
+[22] .data                PROGBITS     0000000000404018 00003018 00000010  0 WA     0   0  8
+[23] .bss                 NOBITS       0000000000404028 00003028 00000008  0 WA     0   0  1
+[24] .comment             PROGBITS     0000000000000000 00003028 0000002a  1 MS     0   0  1
+[25] .ctf                 PROGBITS     0000000000000000 00003052 00000071  0        0   0  1
+[26] .gnu_debuglink       PROGBITS     0000000000000000 000030c4 00000014  0        0   0  4
+[27] .shstrtab            STRTAB       0000000000000000 000030d8 000000fd  0        0   0  1
+
+EOF
+echo readelf testfile.debug
+testrun_compare ${abs_top_builddir}/src/readelf -S testfile.debug <<\EOF
+There are 35 section headers, starting at offset 0xb80:
+
+Section Headers:
+[Nr] Name                 Type         Addr             Off      Size     ES Flags Lk Inf Al
+[ 0]                      NULL         0000000000000000 00000000 00000000  0        0   0  0
+[ 1] .interp              NOBITS       0000000000400318 00000318 0000001c  0 A      0   0  1
+[ 2] .note.gnu.property   NOTE         0000000000400338 00000318 00000020  0 A      0   0  8
+[ 3] .note.ABI-tag        NOTE         0000000000400358 00000338 00000020  0 A      0   0  4
+[ 4] .hash                NOBITS       0000000000400378 00000358 00000018  4 A      6   0  8
+[ 5] .gnu.hash            NOBITS       0000000000400390 00000358 0000001c  0 A      6   0  8
+[ 6] .dynsym              NOBITS       00000000004003b0 00000358 00000048 24 A      7   1  8
+[ 7] .dynstr              NOBITS       00000000004003f8 00000358 00000038  0 A      0   0  1
+[ 8] .gnu.version         NOBITS       0000000000400430 00000358 00000006  2 A      6   0  2
+[ 9] .gnu.version_r       NOBITS       0000000000400438 00000358 00000020  0 A      7   1  8
+[10] .rela.dyn            NOBITS       0000000000400458 00000358 00000030 24 A      6   0  8
+[11] .init                NOBITS       0000000000401000 00000358 00000017  0 AX     0   0  4
+[12] .text                NOBITS       0000000000401020 00000360 00000191  0 AX     0   0 16
+[13] .fini                NOBITS       00000000004011b4 00000360 00000009  0 AX     0   0  4
+[14] .rodata              NOBITS       0000000000402000 00000360 00000004  4 AM     0   0  4
+[15] .eh_frame_hdr        NOBITS       0000000000402004 00000360 00000034  0 A      0   0  4
+[16] .eh_frame            NOBITS       0000000000402038 00000360 000000d8  0 A      0   0  8
+[17] .init_array          NOBITS       0000000000403e40 00000360 00000008  8 WA     0   0  8
+[18] .fini_array          NOBITS       0000000000403e48 00000360 00000008  8 WA     0   0  8
+[19] .dynamic             NOBITS       0000000000403e50 00000360 000001a0 16 WA     7   0  8
+[20] .got                 NOBITS       0000000000403ff0 00000360 00000010  8 WA     0   0  8
+[21] .got.plt             NOBITS       0000000000404000 00000360 00000018  8 WA     0   0  8
+[22] .data                NOBITS       0000000000404018 00000360 00000010  0 WA     0   0  8
+[23] .bss                 NOBITS       0000000000404028 00000360 00000008  0 WA     0   0  1
+[24] .comment             NOBITS       0000000000000000 00000360 0000002a  1 MS     0   0  1
+[25] .ctf                 NOBITS       0000000000000000 00000360 00000071  0        0   0  1
+[26] .debug_aranges       PROGBITS     0000000000000000 00000360 00000030  0        0   0  1
+[27] .debug_info          PROGBITS     0000000000000000 00000390 00000054  0        0   0  1
+[28] .debug_abbrev        PROGBITS     0000000000000000 000003e4 00000038  0        0   0  1
+[29] .debug_line          PROGBITS     0000000000000000 0000041c 0000004f  0        0   0  1
+[30] .debug_str           PROGBITS     0000000000000000 0000046b 0000005f  1 MS     0   0  1
+[31] .debug_line_str      PROGBITS     0000000000000000 000004ca 0000001c  1 MS     0   0  1
+[32] .symtab              SYMTAB       0000000000000000 000004e8 00000378 24       33  20  8
+[33] .strtab              STRTAB       0000000000000000 00000860 000001cb  0        0   0  1
+[34] .shstrtab            STRTAB       0000000000000000 00000a2b 0000014e  0        0   0  1
+
+EOF
+
+# gcc -gctf -g -o testfile-ctf testfile-ctf.c
+# eu-strip --remove-ctf testfile-ctf
+
+# Explicitly removes .ctf section
+echo strip --remove-ctf testfile-ctf
+testrun ${abs_top_builddir}/src/strip --remove-ctf -o testfile.elf -f testfile.debug testfile-ctf
+echo elflint testfile.elf
+testrun ${abs_top_builddir}/src/elflint --gnu testfile.elf
+echo elflint testfile.debug
+testrun ${abs_top_builddir}/src/elflint --gnu -d testfile.debug
+echo readelf testfile.elf
+testrun_compare ${abs_top_builddir}/src/readelf -S testfile.elf <<\EOF
+There are 27 section headers, starting at offset 0x3160:
+
+Section Headers:
+[Nr] Name                 Type         Addr             Off      Size     ES Flags Lk Inf Al
+[ 0]                      NULL         0000000000000000 00000000 00000000  0        0   0  0
+[ 1] .interp              PROGBITS     0000000000400318 00000318 0000001c  0 A      0   0  1
+[ 2] .note.gnu.property   NOTE         0000000000400338 00000338 00000020  0 A      0   0  8
+[ 3] .note.ABI-tag        NOTE         0000000000400358 00000358 00000020  0 A      0   0  4
+[ 4] .hash                HASH         0000000000400378 00000378 00000018  4 A      6   0  8
+[ 5] .gnu.hash            GNU_HASH     0000000000400390 00000390 0000001c  0 A      6   0  8
+[ 6] .dynsym              DYNSYM       00000000004003b0 000003b0 00000048 24 A      7   1  8
+[ 7] .dynstr              STRTAB       00000000004003f8 000003f8 00000038  0 A      0   0  1
+[ 8] .gnu.version         GNU_versym   0000000000400430 00000430 00000006  2 A      6   0  2
+[ 9] .gnu.version_r       GNU_verneed  0000000000400438 00000438 00000020  0 A      7   1  8
+[10] .rela.dyn            RELA         0000000000400458 00000458 00000030 24 A      6   0  8
+[11] .init                PROGBITS     0000000000401000 00001000 00000017  0 AX     0   0  4
+[12] .text                PROGBITS     0000000000401020 00001020 00000191  0 AX     0   0 16
+[13] .fini                PROGBITS     00000000004011b4 000011b4 00000009  0 AX     0   0  4
+[14] .rodata              PROGBITS     0000000000402000 00002000 00000004  4 AM     0   0  4
+[15] .eh_frame_hdr        PROGBITS     0000000000402004 00002004 00000034  0 A      0   0  4
+[16] .eh_frame            PROGBITS     0000000000402038 00002038 000000d8  0 A      0   0  8
+[17] .init_array          INIT_ARRAY   0000000000403e40 00002e40 00000008  8 WA     0   0  8
+[18] .fini_array          FINI_ARRAY   0000000000403e48 00002e48 00000008  8 WA     0   0  8
+[19] .dynamic             DYNAMIC      0000000000403e50 00002e50 000001a0 16 WA     7   0  8
+[20] .got                 PROGBITS     0000000000403ff0 00002ff0 00000010  8 WA     0   0  8
+[21] .got.plt             PROGBITS     0000000000404000 00003000 00000018  8 WA     0   0  8
+[22] .data                PROGBITS     0000000000404018 00003018 00000010  0 WA     0   0  8
+[23] .bss                 NOBITS       0000000000404028 00003028 00000008  0 WA     0   0  1
+[24] .comment             PROGBITS     0000000000000000 00003028 0000002a  1 MS     0   0  1
+[25] .gnu_debuglink       PROGBITS     0000000000000000 00003054 00000014  0        0   0  4
+[26] .shstrtab            STRTAB       0000000000000000 00003068 000000f8  0        0   0  1
+
+EOF
+echo readelf testfile.debug
+testrun_compare ${abs_top_builddir}/src/readelf -S testfile.debug <<\EOF
+There are 35 section headers, starting at offset 0xbf0:
+
+Section Headers:
+[Nr] Name                 Type         Addr             Off      Size     ES Flags Lk Inf Al
+[ 0]                      NULL         0000000000000000 00000000 00000000  0        0   0  0
+[ 1] .interp              NOBITS       0000000000400318 00000318 0000001c  0 A      0   0  1
+[ 2] .note.gnu.property   NOTE         0000000000400338 00000318 00000020  0 A      0   0  8
+[ 3] .note.ABI-tag        NOTE         0000000000400358 00000338 00000020  0 A      0   0  4
+[ 4] .hash                NOBITS       0000000000400378 00000358 00000018  4 A      6   0  8
+[ 5] .gnu.hash            NOBITS       0000000000400390 00000358 0000001c  0 A      6   0  8
+[ 6] .dynsym              NOBITS       00000000004003b0 00000358 00000048 24 A      7   1  8
+[ 7] .dynstr              NOBITS       00000000004003f8 00000358 00000038  0 A      0   0  1
+[ 8] .gnu.version         NOBITS       0000000000400430 00000358 00000006  2 A      6   0  2
+[ 9] .gnu.version_r       NOBITS       0000000000400438 00000358 00000020  0 A      7   1  8
+[10] .rela.dyn            NOBITS       0000000000400458 00000358 00000030 24 A      6   0  8
+[11] .init                NOBITS       0000000000401000 00000358 00000017  0 AX     0   0  4
+[12] .text                NOBITS       0000000000401020 00000360 00000191  0 AX     0   0 16
+[13] .fini                NOBITS       00000000004011b4 00000360 00000009  0 AX     0   0  4
+[14] .rodata              NOBITS       0000000000402000 00000360 00000004  4 AM     0   0  4
+[15] .eh_frame_hdr        NOBITS       0000000000402004 00000360 00000034  0 A      0   0  4
+[16] .eh_frame            NOBITS       0000000000402038 00000360 000000d8  0 A      0   0  8
+[17] .init_array          NOBITS       0000000000403e40 00000360 00000008  8 WA     0   0  8
+[18] .fini_array          NOBITS       0000000000403e48 00000360 00000008  8 WA     0   0  8
+[19] .dynamic             NOBITS       0000000000403e50 00000360 000001a0 16 WA     7   0  8
+[20] .got                 NOBITS       0000000000403ff0 00000360 00000010  8 WA     0   0  8
+[21] .got.plt             NOBITS       0000000000404000 00000360 00000018  8 WA     0   0  8
+[22] .data                NOBITS       0000000000404018 00000360 00000010  0 WA     0   0  8
+[23] .bss                 NOBITS       0000000000404028 00000360 00000008  0 WA     0   0  1
+[24] .comment             NOBITS       0000000000000000 00000360 0000002a  1 MS     0   0  1
+[25] .ctf                 PROGBITS     0000000000000000 00000360 00000071  0        0   0  1
+[26] .debug_aranges       PROGBITS     0000000000000000 000003d1 00000030  0        0   0  1
+[27] .debug_info          PROGBITS     0000000000000000 00000401 00000054  0        0   0  1
+[28] .debug_abbrev        PROGBITS     0000000000000000 00000455 00000038  0        0   0  1
+[29] .debug_line          PROGBITS     0000000000000000 0000048d 0000004f  0        0   0  1
+[30] .debug_str           PROGBITS     0000000000000000 000004dc 0000005f  1 MS     0   0  1
+[31] .debug_line_str      PROGBITS     0000000000000000 0000053b 0000001c  1 MS     0   0  1
+[32] .symtab              SYMTAB       0000000000000000 00000558 00000378 24       33  20  8
+[33] .strtab              STRTAB       0000000000000000 000008d0 000001cb  0        0   0  1
+[34] .shstrtab            STRTAB       0000000000000000 00000a9b 0000014e  0        0   0  1
+
+EOF
+
+exit 0
diff --git a/tests/testfile-ctf.bz2 b/tests/testfile-ctf.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..f48bb9304f1e2194500f5091dbb3aa1a7b8806cc