/* GNU PIC object symbol strip
Copyright 2005 Craig Franklin
Copyright 2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
#include "gpstrip.h"
#include <list>
struct gpstrip_state state;
static bool verbose;
static const char longopts[] =
"gstrip-debug\0"
"hhelp\0"
"kkeep-symbol\1SYMBOL\0"
"nstrip-symbol\1SYMBOL\0"
"ooutput\1FILE\0"
"ppreserve-dates\0"
"rremove-section\1SECTION\0"
"\1strict-options\0"
"sstrip-all\0"
"ustrip-unneeded\0"
"vversion\0"
"Vverbose\0"
"xdiscard-all\0";
static const char longdesc[] =
"Strip debug symbols.\0"
"Show this usage message.\0"
"Keep symbol.\0"
"Remove symbol.\0"
"Alternate name of output file.\0"
"Preserve dates.\0"
"Remove section.\0"
"If this is set, then an option may not be parameter"
" of an another option. For example: -o --version\0"
"Remove all symbols.\0"
"Strip symbols not need for relocations.\0"
"Show version.\0"
"Verbose mode.\0"
"Remove non-global symbols.\0";
/*------------------------------------------------------------------------------------------------*/
static void _show_usage(const char*argv0) {
printf("Usage: %s [options] file(s)\n",argv0);
gp_usage(0,longopts,longdesc,40);
exit(0);
}
/*------------------------------------------------------------------------------------------------*/
static gp_symbol_list_t::iterator _conditional_remove(gp_symbol_list_t::iterator Symbol) {
const symbol_t *sym;
sym = gp_sym_get_symbol(state.symbol_keep, Symbol->name);
if (!sym) {
if (verbose) {
gp_message("removing symbol \"%s\"", Symbol->name);
}
return state.object->gp_coffgen_del_symbol(Symbol, true);
}
return ++Symbol;
}
/*------------------------------------------------------------------------------------------------*/
static void _remove_sections() {
size_t i;
const symbol_t *sym;
gp_section_t *section;
/* FIXME: Check for relocations from other sections. Error out if they exist. */
for (i = 0; i < gp_sym_get_symbol_count(state.section_remove); ++i) {
sym = gp_sym_get_symbol_with_index(state.section_remove, i);
section = gp_coffgen_find_section(state.object, state.object->section_list.first, gp_sym_get_symbol_name(sym));
if (section) {
if (verbose) {
gp_message("removing section \"%s\"", gp_sym_get_symbol_name(sym));
}
/* remove the sections symbols */
gp_coffgen_del_section_symbols(state.object, section);
/* remove the section */
gp_coffgen_del_section(state.object, section);
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void _remove_symbols() {
size_t i;
const symbol_t *sym;
for (i = 0; i < gp_sym_get_symbol_count(state.symbol_remove); ++i) {
sym = gp_sym_get_symbol_with_index(state.symbol_remove, i);
gp_symbol_list_t::iterator symbol = state.object->gp_coffgen_find_symbol(gp_sym_get_symbol_name(sym));
if (&*symbol) {
if (!symbol->gp_coffgen_symbol_has_reloc(COFF_SYM_RELOC_ALL)) {
_conditional_remove(symbol);
}
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void _strip_all() {
gp_section_t *section;
if (state.object->flags & F_EXEC) {
section = state.object->section_list.first;
while (section) {
/* Remove the line numbers, have too because the symbols will be removed. */
gp_list_delete(§ion->line_number_list);
/* Remove the relocations, they should already be removed. */
gp_list_delete(§ion->relocation_list);
section = section->next;
}
/* remove all symbols */
state.object->num_symbols = 0;
gp_list_delete(&state.object->symbol_list);
}
else {
gp_error("can not strip all symbols because the object file is not executable");
}
}
/*------------------------------------------------------------------------------------------------*/
static void _strip_debug() {
gp_section_t *section = state.object->section_list.first;
while (section) {
/* remove the line numbers */
gp_list_delete(§ion->line_number_list);
section = section->next;
}
gp_symbol_list_t::iterator it = state.object->symbol_list.begin();
while (it!=state.object->symbol_list.end()) {
/* remove any debug symbols */
if (it->section_number == N_DEBUG) {
_conditional_remove(it);
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void _strip_unneeded() {
gp_symbol_list_t&syms = state.object->symbol_list;
gp_symbol_list_t::iterator sym = syms.begin();
while (sym!=syms.end()) {
/* If the symbol has a relocation or is global it can't be removed. */
if (!sym->gp_coffgen_symbol_has_reloc(COFF_SYM_RELOC_ALL) && !sym->gp_coffgen_is_global_symbol()) {
sym = _conditional_remove(sym);
}else ++sym;
}
}
/*------------------------------------------------------------------------------------------------*/
static void _discard_all() {
gp_symbol_list_t&syms = state.object->symbol_list;
gp_symbol_list_t::iterator sym = syms.begin();
while (sym!=syms.end()) {
if (!sym->gp_coffgen_is_global_symbol()) {
sym = _conditional_remove(sym);
}else ++sym;
}
}
/*------------------------------------------------------------------------------------------------*/
static void _add_name(symbol_table_t *Table, const char *Name) {
const symbol_t*sym = gp_sym_get_symbol(Table, Name);
if (!sym) gp_sym_add_symbol(Table, Name);
}
/*------------------------------------------------------------------------------------------------*/
static bool strict_options, usage;
static std::list<const char*>files;
static void _stdcall onOption(void*,char c, const char*arg) {
if (strict_options) gp_checkarg(arg,longopts);
switch (c) {
case '?':
case 'h': usage = true; break;
case 'g': state.strip_debug = true; break;
case 'k': _add_name(state.symbol_keep,arg); break;
case 'n': _add_name(state.symbol_remove,arg);break;
case 'o': state.output_file = arg; break;
case 'p': state.preserve_dates = true; break;
case 'r': _add_name(state.section_remove,arg);break;
case 's': state.strip_all = true; break;
case 'u': state.strip_unneeded = true; break;
case 'x': state.discard_all = true; break;
case 'V': verbose = true; break;
case 'v':
fprintf(stderr, "%s\n", GPSTRIP_VERSION_STRING);
exit(0);
case 1: strict_options = true; break;
case 0: files.push_back(arg); break;
}
}
int main(int argc, char *argv[]) {
gp_init();
/* initalize */
state.symbol_keep = gp_sym_push_table(NULL, false);
state.symbol_remove = gp_sym_push_table(NULL, false);
state.section_remove = gp_sym_push_table(NULL, false);
gp_getopt(argv,longopts,onOption);
if (files.empty() || usage) _show_usage(*argv);
for (std::list<const char*>::iterator it=files.begin(); it!=files.end(); ++it) {
state.input_file = *it;
if ((gp_identify_coff_file(state.input_file) != GP_COFF_OBJECT_V2) &&
(gp_identify_coff_file(state.input_file) != GP_COFF_OBJECT)) {
gp_error("\"%s\" is not a valid object file", state.input_file);
exit(1);
}
state.object = gp_read_coff(state.input_file);
if (state.object) {
_remove_sections();
_remove_symbols();
if (state.strip_all) {
_strip_all();
}
if (state.strip_debug) {
if (state.strip_all) {
gp_message("strip debug ignored");
}
else {
_strip_debug();
}
}
if (state.strip_unneeded) {
if (state.strip_all) {
gp_message("strip unneeded ignored");
}
else {
_strip_unneeded();
}
}
if (state.discard_all) {
if (state.strip_all) {
gp_message("discard all ignored");
}
else {
_discard_all();
}
}
if (state.output_file) {
state.object->filename = state.output_file;
}
if (!state.preserve_dates) {
/* FIXME: need to update the output file dates */
state.object->time = (long)time(NULL);
}
if (!gp_num.errors) {
/* no errors have occured so write the file */
if (!gp_writeobj_write_coff(state.object, 0)) {
gp_error("system error while writing object file");
}
}
else if (state.output_file) {
/* A pnew file is being written, but errors have occurred, delete the file if it exists. */
unlink(state.output_file);
}
/* FIXME: free state.output_file */
}
}
return gp_num.errors ? EXIT_FAILURE : EXIT_SUCCESS;
}
Vorgefundene Kodierung: UTF-8 | 0
|