summaryrefslogtreecommitdiffstats
path: root/src/strip.c
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2017-07-14 17:09:40 +0200
committerMark Wielaard <[email protected]>2017-07-17 13:35:33 +0200
commitd03be4f70c688a8c675935973663014c3c4bba76 (patch)
tree3e931ae49814da48d61cd18c64377306587a8e0a /src/strip.c
parentd65648473d1bfc779e16cd3cbf140a8ba0fed16c (diff)
strip: Add --keep-section=SECTION and --remove-section=SECTION.
Adds two new output options: --keep-section=SECTION Keep the named section. SECTION is an extended wildcard pattern. May be given more than once. --remove-section=SECTION Remove the named section. SECTION is an extended wildcard pattern. May be given more than once. Only non-allocated sections can be removed. The --remove-section was already partially implemented, but only for the .comment section. The short option -R is to be compatible with binutils. The new testcase makes sure that various combinations of kept/removed sections pull the correct dependencies into the output and/or debug files. https://bugzilla.redhat.com/show_bug.cgi?id=1465997 Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'src/strip.c')
-rw-r--r--src/strip.c127
1 files changed, 110 insertions, 17 deletions
diff --git a/src/strip.c b/src/strip.c
index 2bf95f90..4a35ea1d 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -26,6 +26,7 @@
#include <endian.h>
#include <error.h>
#include <fcntl.h>
+#include <fnmatch.h>
#include <gelf.h>
#include <libelf.h>
#include <libintl.h>
@@ -60,6 +61,7 @@ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
#define OPT_PERMISSIVE 0x101
#define OPT_STRIP_SECTIONS 0x102
#define OPT_RELOC_DEBUG 0x103
+#define OPT_KEEP_SECTION 0x104
/* Definitions of arguments for argp functions. */
@@ -83,7 +85,8 @@ static const struct argp_option options[] =
N_("Resolve all trivial relocations between debug sections if the removed sections are placed in a debug file (only relevant for ET_REL files, operation is not reversable, needs -f)"), 0 },
{ "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
N_("Remove .comment section"), 0 },
- { "remove-section", 'R', "SECTION", OPTION_HIDDEN, NULL, 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,
N_("Relax a few rules to handle slightly broken ELF files"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
@@ -157,6 +160,58 @@ static bool permissive;
/* If true perform relocations between debug sections. */
static bool reloc_debug;
+/* Sections the user explicitly wants to keep or remove. */
+struct section_pattern
+{
+ char *pattern;
+ struct section_pattern *next;
+};
+
+static struct section_pattern *keep_secs = NULL;
+static struct section_pattern *remove_secs = NULL;
+
+static void
+add_pattern (struct section_pattern **patterns, const char *pattern)
+{
+ struct section_pattern *p = xmalloc (sizeof *p);
+ p->pattern = xstrdup (pattern);
+ p->next = *patterns;
+ *patterns = p;
+}
+
+static void
+free_sec_patterns (struct section_pattern *patterns)
+{
+ struct section_pattern *pattern = patterns;
+ while (pattern != NULL)
+ {
+ struct section_pattern *p = pattern;
+ pattern = p->next;
+ free (p->pattern);
+ free (p);
+ }
+}
+
+static void
+free_patterns (void)
+{
+ free_sec_patterns (keep_secs);
+ free_sec_patterns (remove_secs);
+}
+
+static bool
+section_name_matches (struct section_pattern *patterns, const char *name)
+{
+ struct section_pattern *pattern = patterns;
+ while (pattern != NULL)
+ {
+ if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
+ return true;
+ pattern = pattern->next;
+ }
+ return false;
+}
+
int
main (int argc, char *argv[])
@@ -207,6 +262,7 @@ Only one input file allowed together with '-o' and '-f'"));
while (++remaining < argc);
}
+ free_patterns ();
return result;
}
@@ -257,14 +313,13 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'R':
- if (!strcmp (arg, ".comment"))
+ if (fnmatch (arg, ".comment", FNM_EXTMATCH) == 0)
remove_comment = true;
- else
- {
- argp_error (state,
- gettext ("-R option supports only .comment section"));
- return EINVAL;
- }
+ add_pattern (&remove_secs, arg);
+ break;
+
+ case OPT_KEEP_SECTION:
+ add_pattern (&keep_secs, arg);
break;
case 'g':
@@ -284,6 +339,16 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 's': /* Ignored for compatibility. */
break;
+ case ARGP_KEY_SUCCESS:
+ if (remove_comment == true
+ && section_name_matches (keep_secs, ".comment"))
+ {
+ argp_error (state,
+ gettext ("cannot both keep and remove .comment section"));
+ return EINVAL;
+ }
+ break;
+
default:
return ARGP_ERR_UNKNOWN;
}
@@ -622,6 +687,28 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
goto fail_close;
}
+ /* Sanity check the user. */
+ if (section_name_matches (remove_secs, shdr_info[cnt].name))
+ {
+ if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0)
+ {
+ error (0, 0,
+ gettext ("Cannot remove allocated section '%s'"),
+ shdr_info[cnt].name);
+ result = 1;
+ goto fail_close;
+ }
+
+ if (section_name_matches (keep_secs, shdr_info[cnt].name))
+ {
+ error (0, 0,
+ gettext ("Cannot both keep and remove section '%s'"),
+ shdr_info[cnt].name);
+ result = 1;
+ goto fail_close;
+ }
+ }
+
/* Mark them as present but not yet investigated. */
shdr_info[cnt].idx = 1;
@@ -709,6 +796,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
know how to handle them
- if a section is referred to from a section which is not removed
in the sh_link or sh_info element it cannot be removed either
+ - the user might have explicitly said to remove or keep a section
*/
for (cnt = 1; cnt < shnum; ++cnt)
/* Check whether the section can be removed. Since we will create
@@ -717,8 +805,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
: (ebl_section_strip_p (ebl, ehdr, &shdr_info[cnt].shdr,
shdr_info[cnt].name, remove_comment,
remove_debug)
- || cnt == ehdr->e_shstrndx))
+ || cnt == ehdr->e_shstrndx
+ || section_name_matches (remove_secs, shdr_info[cnt].name)))
{
+ /* The user might want to explicitly keep this one. */
+ if (section_name_matches (keep_secs, shdr_info[cnt].name))
+ continue;
+
/* For now assume this section will be removed. */
shdr_info[cnt].idx = 0;
@@ -2174,14 +2267,14 @@ while computing checksum for debug information"));
if (shdr_info != NULL)
{
/* For some sections we might have created an table to map symbol
- table indices. */
- if (any_symtab_changes)
- for (cnt = 1; cnt <= shdridx; ++cnt)
- {
- free (shdr_info[cnt].newsymidx);
- if (shdr_info[cnt].debug_data != NULL)
- free (shdr_info[cnt].debug_data->d_buf);
- }
+ table indices. Or we might kept (original) data around to put
+ into the .debug file. */
+ for (cnt = 1; cnt <= shdridx; ++cnt)
+ {
+ free (shdr_info[cnt].newsymidx);
+ if (shdr_info[cnt].debug_data != NULL)
+ free (shdr_info[cnt].debug_data->d_buf);
+ }
/* Free data we allocated for the .gnu_debuglink section. */
free (debuglink_buf);