186 lines
6.3 KiB
C
186 lines
6.3 KiB
C
#include <debug.h>
|
|
#include <cmdline.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
extern char *optarg;
|
|
extern int optind, opterr, optopt;
|
|
|
|
static struct option long_options[] = {
|
|
{"start-address", required_argument, 0, 's'},
|
|
{"inc-address", required_argument, 0, 'i'},
|
|
{"locals-only", no_argument, 0, 'l'},
|
|
{"quiet", no_argument, 0, 'Q'},
|
|
{"noupdate", no_argument, 0, 'n'},
|
|
{"lookup", required_argument, 0, 'L'},
|
|
{"default", required_argument, 0, 'D'},
|
|
{"verbose", no_argument, 0, 'V'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{"mapfile", required_argument, 0, 'M'},
|
|
{"output", required_argument, 0, 'o'},
|
|
{"prelinkmap", required_argument, 0, 'p'},
|
|
{0, 0, 0, 0},
|
|
};
|
|
|
|
/* This array must parallel long_options[] */
|
|
static const char *descriptions[] = {
|
|
"start address to prelink libraries to",
|
|
"address increment for each library",
|
|
"prelink local relocations only",
|
|
"suppress informational and non-fatal error messages",
|
|
"do a dry run--calculate the prelink info but do not update any files",
|
|
"provide a directory for library lookup",
|
|
"provide a default library or executable for symbol lookup",
|
|
"print verbose output",
|
|
"print help screen",
|
|
"print a list of prelink addresses to file (prefix filename with + to append instead of overwrite)",
|
|
"specify an output directory (if multiple inputs) or file (is single input)",
|
|
"specify a file with prelink addresses instead of a --start-address/--inc-address combination",
|
|
};
|
|
|
|
void print_help(const char *name) {
|
|
fprintf(stdout,
|
|
"invokation:\n"
|
|
"\t%s file1 [file2 file3 ...] -Ldir1 [-Ldir2 ...] -saddr -iinc [-Vqn] [-M<logfile>]\n"
|
|
"\t%s -l file [-Vqn] [-M<logfile>]\n"
|
|
"\t%s -h\n\n", name, name, name);
|
|
fprintf(stdout, "options:\n");
|
|
struct option *opt = long_options;
|
|
const char **desc = descriptions;
|
|
while (opt->name) {
|
|
fprintf(stdout, "\t-%c/--%s%s: %s\n",
|
|
opt->val,
|
|
opt->name,
|
|
(opt->has_arg ? " (argument)" : ""),
|
|
*desc);
|
|
opt++;
|
|
desc++;
|
|
}
|
|
}
|
|
|
|
int get_options(int argc, char **argv,
|
|
int *start_addr,
|
|
int *inc_addr,
|
|
int *locals_only,
|
|
int *quiet,
|
|
int *dry_run,
|
|
char ***dirs,
|
|
int *num_dirs,
|
|
char ***defaults,
|
|
int *num_defaults,
|
|
int *verbose,
|
|
char **mapfile,
|
|
char **output,
|
|
char **prelinkmap) {
|
|
int c;
|
|
|
|
ASSERT(dry_run); *dry_run = 0;
|
|
ASSERT(quiet); *quiet = 0;
|
|
ASSERT(verbose); *verbose = 0;
|
|
ASSERT(dirs); *dirs = NULL;
|
|
ASSERT(num_dirs); *num_dirs = 0;
|
|
ASSERT(defaults); *defaults = NULL;
|
|
ASSERT(num_defaults); *num_defaults = 0;
|
|
ASSERT(start_addr); *start_addr = -1;
|
|
ASSERT(inc_addr); *inc_addr = -1;
|
|
ASSERT(locals_only); *locals_only = 0;
|
|
ASSERT(mapfile); *mapfile = NULL;
|
|
ASSERT(output); *output = NULL;
|
|
ASSERT(prelinkmap); *prelinkmap = NULL;
|
|
int dirs_size = 0;
|
|
int defaults_size = 0;
|
|
|
|
while (1) {
|
|
/* getopt_long stores the option index here. */
|
|
int option_index = 0;
|
|
|
|
c = getopt_long (argc, argv,
|
|
"VhnQlL:D:s:i:M:o:p:",
|
|
long_options,
|
|
&option_index);
|
|
/* Detect the end of the options. */
|
|
if (c == -1) break;
|
|
|
|
if (isgraph(c)) {
|
|
INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
|
|
}
|
|
|
|
#define SET_STRING_OPTION(name) do { \
|
|
ASSERT(optarg); \
|
|
(*name) = strdup(optarg); \
|
|
} while(0)
|
|
|
|
#define SET_REPEATED_STRING_OPTION(arr, num, size) do { \
|
|
if (*num == size) { \
|
|
size += 10; \
|
|
*arr = (char **)REALLOC(*arr, size * sizeof(char *)); \
|
|
} \
|
|
SET_STRING_OPTION(((*arr) + *num)); \
|
|
(*num)++; \
|
|
} while(0)
|
|
|
|
#define SET_INT_OPTION(val) do { \
|
|
ASSERT(optarg); \
|
|
if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \
|
|
FAILIF(1 != sscanf(optarg+2, "%x", val), \
|
|
"Expecting a hexadecimal argument!\n"); \
|
|
} else { \
|
|
FAILIF(1 != sscanf(optarg, "%d", val), \
|
|
"Expecting a decimal argument!\n"); \
|
|
} \
|
|
} while(0)
|
|
|
|
switch (c) {
|
|
case 0:
|
|
/* If this option set a flag, do nothing else now. */
|
|
if (long_options[option_index].flag != 0)
|
|
break;
|
|
INFO ("option %s", long_options[option_index].name);
|
|
if (optarg)
|
|
INFO (" with arg %s", optarg);
|
|
INFO ("\n");
|
|
break;
|
|
case 'Q': *quiet = 1; break;
|
|
case 'n': *dry_run = 1; break;
|
|
case 'M':
|
|
SET_STRING_OPTION(mapfile);
|
|
break;
|
|
case 'o':
|
|
SET_STRING_OPTION(output);
|
|
break;
|
|
case 'p':
|
|
SET_STRING_OPTION(prelinkmap);
|
|
break;
|
|
case 's':
|
|
SET_INT_OPTION(start_addr);
|
|
break;
|
|
case 'i':
|
|
SET_INT_OPTION(inc_addr);
|
|
break;
|
|
case 'L':
|
|
SET_REPEATED_STRING_OPTION(dirs, num_dirs, dirs_size);
|
|
break;
|
|
case 'D':
|
|
SET_REPEATED_STRING_OPTION(defaults, num_defaults, defaults_size);
|
|
break;
|
|
case 'l': *locals_only = 1; break;
|
|
case 'h': print_help(argv[0]); exit(1); break;
|
|
case 'V': *verbose = 1; break;
|
|
case '?':
|
|
/* getopt_long already printed an error message. */
|
|
break;
|
|
|
|
#undef SET_STRING_OPTION
|
|
#undef SET_REPEATED_STRING_OPTION
|
|
#undef SET_INT_OPTION
|
|
|
|
default:
|
|
FAILIF(1, "Unknown option");
|
|
}
|
|
}
|
|
|
|
return optind;
|
|
}
|