diff options
| author | Mark Wielaard <[email protected]> | 2017-07-14 17:09:40 +0200 |
|---|---|---|
| committer | Mark Wielaard <[email protected]> | 2017-07-17 13:35:33 +0200 |
| commit | d03be4f70c688a8c675935973663014c3c4bba76 (patch) | |
| tree | 3e931ae49814da48d61cd18c64377306587a8e0a /src/strip.c | |
| parent | d65648473d1bfc779e16cd3cbf140a8ba0fed16c (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.c | 127 |
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); |
