Skip to content

Commit

Permalink
Added fatelf-split utility.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Sep 25, 2009
1 parent 2194796 commit e1488bd
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 53 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -10,6 +10,7 @@ ADD_EXECUTABLE(fatelf-extract utils/fatelf-extract.c utils/fatelf-utils.c)
ADD_EXECUTABLE(fatelf-replace utils/fatelf-replace.c utils/fatelf-utils.c)
ADD_EXECUTABLE(fatelf-remove utils/fatelf-remove.c utils/fatelf-utils.c)
ADD_EXECUTABLE(fatelf-verify utils/fatelf-verify.c utils/fatelf-utils.c)
ADD_EXECUTABLE(fatelf-split utils/fatelf-split.c utils/fatelf-utils.c)

# end of CMakeLists.txt ...

40 changes: 4 additions & 36 deletions utils/fatelf-info.c
Expand Up @@ -9,36 +9,6 @@
#define FATELF_UTILS 1
#include "fatelf-utils.h"

static const char *get_wordsize(const uint8_t wordsize)
{
if (wordsize == FATELF_32BITS)
return "32";
else if (wordsize == FATELF_64BITS)
return "64";
return "???";
} // get_wordsize


static const char *get_byteorder_name(const uint8_t byteorder)
{
if (byteorder == FATELF_LITTLEENDIAN)
return "Littleendian";
else if (byteorder == FATELF_BIGENDIAN)
return "Bigendian";
return "???";
} // get_byteorder_name


static const char *get_byteorder_target_name(const uint8_t byteorder)
{
if (byteorder == FATELF_LITTLEENDIAN)
return "le";
else if (byteorder == FATELF_BIGENDIAN)
return "be";
return "";
} // get_byteorder_target_name


static int fatelf_info(const char *fname)
{
const int fd = xopen(fname, O_RDONLY, 0755);
Expand All @@ -59,17 +29,15 @@ static int fatelf_info(const char *fname)
(unsigned int) rec->osabi, osabi ? osabi->name : "???",
osabi ? ": " : "", osabi ? osabi->desc : "",
(unsigned int) rec->osabi_version);
printf(" %s bits\n", get_wordsize(rec->word_size));
printf(" %s byteorder\n", get_byteorder_name(rec->byte_order));
printf(" %s bits\n", fatelf_get_wordsize_string(rec->word_size));
printf(" %s byteorder\n", fatelf_get_byteorder_name(rec->byte_order));
printf(" Machine %u (%s%s%s)\n",
(unsigned int) rec->machine, machine ? machine->name : "???",
machine ? ": " : "", machine ? machine->desc : "");
printf(" Offset %llu\n", (unsigned long long) rec->offset);
printf(" Size %llu\n", (unsigned long long) rec->size);
printf(" Target string: '%s:%sbits:%s:%s:osabiver%d' or 'record%u'\n",
machine ? machine->name : "", get_wordsize(rec->word_size),
get_byteorder_target_name(rec->byte_order),
osabi ? osabi->name : "", (int) rec->osabi_version, i);
printf(" Target string: '%s' or 'record%u'\n",
fatelf_get_target_string(rec, FATELF_WANT_EVERYTHING), i);
} // for

xclose(fname, fd);
Expand Down
141 changes: 141 additions & 0 deletions utils/fatelf-split.c
@@ -0,0 +1,141 @@
/**
* FatELF; support multiple ELF binaries in one file.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/

#define FATELF_UTILS 1
#include "fatelf-utils.h"

static char *make_filename(const char *base, const int wants,
const FATELF_record *rec)
{
const char *target = fatelf_get_target_string(rec, wants);
const size_t len = strlen(base) + strlen(target) + 2;
char *retval = (char *) xmalloc(len);
snprintf(retval, len, "%s-%s", base, target);
return retval;
} // make_filename


static inline int unsorted(const FATELF_record *a, const FATELF_record *b)
{
#define TEST_UNSORTED(field) \
if (a->field > b->field) \
return 1; \
else if (a->field < b->field) \
return 0;

// This is the in order of precedence of fields.
TEST_UNSORTED(machine);
TEST_UNSORTED(word_size);
TEST_UNSORTED(byte_order);
TEST_UNSORTED(osabi);
TEST_UNSORTED(osabi_version);

#undef TEST_UNSORTED

return 0;
} // unsorted


static int fatelf_split(const char *fname)
{
const int fd = xopen(fname, O_RDONLY, 0755);
FATELF_header *header = xread_fatelf_header(fname, fd);
const size_t len = sizeof (FATELF_record *) * header->num_records;
FATELF_record **sorted = (FATELF_record **) xmalloc(len);
const int maxrecs = header->num_records;
int is_sorted = 1;
int i = 0;

// Try to keep the filenames as short as possible. To start, sort
// the records so we know which items are relevant.
for (i = 0; i < ((int) header->num_records); i++)
sorted[i] = &header->records[i];

do // bubble sort ftw.
{
is_sorted = 1;
for (i = 0; i < ((int)header->num_records)-1; i++)
{
if (unsorted(sorted[i], sorted[i+1]))
{
FATELF_record *tmp = sorted[i];
sorted[i] = sorted[i+1];
sorted[i+1] = tmp;
is_sorted = 0;
} // if
} // for
} while (!is_sorted);

// now dump each ELF file, naming it with just the minimum set of
// attributes that make it unique. We do this by checking the item
// sorted before it and after it to see what matches.

// This isn't perfect...you might get a list like this case...
//
// mybin-i386
// mybin-ppc:32bits:be
// mybin-ppc:32bits:le
// mybin-ppc64
// mybin-x86_64
//
// ...where those "32bits:" parts are superfluous.

for (i = 0; i < maxrecs; i++)
{
const FATELF_record *rec = sorted[i];
const FATELF_record *prev = (i > 0) ? sorted[i-1] : NULL;
const FATELF_record *next = (i < maxrecs-1) ? sorted[i+1] : NULL;
char *out = NULL;
int outfd = -1;
int wants = 0;
int unique = 0;

#define TEST_WANT(field, flag) \
if (!unique) { \
wants |= FATELF_WANT_##flag; \
if ((prev) && (prev->field != rec->field)) prev = NULL; \
if ((next) && (next->field != rec->field)) next = NULL; \
if (!prev && !next) unique = 1; \
}

// This must be in the same order as the TEST_UNSORTED things above.
TEST_WANT(machine, MACHINE);
TEST_WANT(word_size, WORDSIZE);
TEST_WANT(byte_order, BYTEORDER);
TEST_WANT(osabi, OSABI);
TEST_WANT(osabi_version, OSABIVER);

#undef TEST_WANT

out = make_filename(fname, wants, rec);
outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755);
unlink_on_xfail = out;
xcopyfile_range(fname, fd, out, outfd, rec->offset, rec->size);
xclose(out, outfd);
unlink_on_xfail = NULL;
free(out);
} // for

free(sorted);
xclose(fname, fd);
free(header);

return 0; // success.
} // fatelf_split


int main(int argc, const char **argv)
{
xfatelf_init(argc, argv);
if (argc != 2) // this could stand to use getopt(), later.
xfail("USAGE: %s <in>", argv[0]);
return fatelf_split(argv[1]);
} // main

// end of fatelf-split.c ...

123 changes: 106 additions & 17 deletions utils/fatelf-utils.c
Expand Up @@ -590,11 +590,7 @@ static int xfind_fatelf_record_by_fields(const FATELF_header *header,
const fatelf_osabi_info *osabi = NULL;
const fatelf_machine_info *machine = NULL;
FATELF_record rec;
int want_machine = 0;
int want_osabi = 0;
int want_osabiver = 0;
int want_wordsize = 0;
int want_byteorder = 0;
int wants = 0;
int abiver = 0;
char *str = buf;
char *ptr = buf;
Expand All @@ -614,37 +610,37 @@ static int xfind_fatelf_record_by_fields(const FATELF_header *header,
} // if
else if ((strcmp(str,"be")==0) || (strcmp(str,"bigendian")==0))
{
want_byteorder = 1;
wants |= FATELF_WANT_BYTEORDER;
rec.byte_order = FATELF_BIGENDIAN;
} // if
else if ((strcmp(str,"le")==0) || (strcmp(str,"littleendian")==0))
{
want_byteorder = 1;
wants |= FATELF_WANT_BYTEORDER;
rec.byte_order = FATELF_LITTLEENDIAN;
} // else if
else if (strcmp(str,"32bit") == 0)
{
want_wordsize = 1;
wants |= FATELF_WANT_WORDSIZE;
rec.word_size = FATELF_32BITS;
} // else if
else if (strcmp(str,"64bit") == 0)
{
want_wordsize = 1;
wants |= FATELF_WANT_WORDSIZE;
rec.word_size = FATELF_64BITS;
} // else if
else if ((machine = get_machine_by_name(str)) != NULL)
{
want_machine = 1;
wants |= FATELF_WANT_MACHINE;
rec.machine = machine->id;
} // else if
else if ((osabi = get_osabi_by_name(str)) != NULL)
{
want_osabi = 1;
wants |= FATELF_WANT_OSABI;
rec.osabi = osabi->id;
} // else if
else if ((abiver = parse_abi_version_string(str)) != -1)
{
want_osabiver = 1;
wants |= FATELF_WANT_OSABIVER;
rec.osabi_version = (uint8_t) abiver;
} // else if
else
Expand All @@ -666,15 +662,15 @@ static int xfind_fatelf_record_by_fields(const FATELF_header *header,
for (i = 0; i < ((int) header->num_records); i++)
{
const FATELF_record *prec = &header->records[i];
if ((want_machine) && (rec.machine != prec->machine))
if ((wants & FATELF_WANT_MACHINE) && (rec.machine != prec->machine))
continue;
else if ((want_osabi) && (rec.osabi != prec->osabi))
else if ((wants & FATELF_WANT_OSABI) && (rec.osabi != prec->osabi))
continue;
else if ((want_osabiver) && (rec.osabi_version != prec->osabi_version))
else if ((wants & FATELF_WANT_OSABIVER) && (rec.osabi_version != prec->osabi_version))
continue;
else if ((want_wordsize) && (rec.word_size != prec->word_size))
else if ((wants & FATELF_WANT_WORDSIZE) && (rec.word_size != prec->word_size))
continue;
else if ((want_byteorder) && (rec.byte_order != prec->byte_order))
else if ((wants & FATELF_WANT_BYTEORDER) && (rec.byte_order != prec->byte_order))
continue;

if (retval != -1)
Expand Down Expand Up @@ -718,6 +714,99 @@ int fatelf_record_matches(const FATELF_record *a, const FATELF_record *b)
} // fatelf_record_matches


const char *fatelf_get_wordsize_string(const uint8_t wordsize)
{
if (wordsize == FATELF_32BITS)
return "32";
else if (wordsize == FATELF_64BITS)
return "64";
return "???";
} // fatelf_get_wordsize_string


const char *fatelf_get_byteorder_name(const uint8_t byteorder)
{
if (byteorder == FATELF_LITTLEENDIAN)
return "Littleendian";
else if (byteorder == FATELF_BIGENDIAN)
return "Bigendian";
return "???";
} // get_byteorder_name


static const char *get_byteorder_target_name(const uint8_t byteorder)
{
if (byteorder == FATELF_LITTLEENDIAN)
return "le";
else if (byteorder == FATELF_BIGENDIAN)
return "be";
return NULL;
} // get_byteorder_target_name


const char *get_wordsize_name(const uint8_t wordsize)
{
if (wordsize == FATELF_32BITS)
return "32bits";
else if (wordsize == FATELF_64BITS)
return "64bits";
return NULL;
} // get_wordsize_name



const char *fatelf_get_target_string(const FATELF_record *rec, const int wants)
{
// !!! FIXME: this code is sort of stinky.
static char buffer[128];
const fatelf_osabi_info *osabi = get_osabi_by_id(rec->osabi);
const fatelf_machine_info *machine = get_machine_by_id(rec->machine);
const char *order = get_byteorder_target_name(rec->byte_order);
const char *wordsize = get_wordsize_name(rec->word_size);

buffer[0] = '\0';

if ((wants & FATELF_WANT_MACHINE) && (machine))
{
if (buffer[0])
strcat(buffer, ":");
strcat(buffer, machine->name);
} // if

if ((wants & FATELF_WANT_WORDSIZE) && (wordsize))
{
if (buffer[0])
strcat(buffer, ":");
strcat(buffer, wordsize);
} // if

if ((wants & FATELF_WANT_BYTEORDER) && (order))
{
if (buffer[0])
strcat(buffer, ":");
strcat(buffer, order);
} // if

if ((wants & FATELF_WANT_OSABI) && (osabi))
{
if (buffer[0])
strcat(buffer, ":");
strcat(buffer, osabi->name);
} // if

if (wants & FATELF_WANT_OSABIVER)
{
char tmp[32];
if (buffer[0])
strcat(buffer, ":");
snprintf(tmp, sizeof (tmp), "osabiver%d", (int) rec->osabi_version);
strcat(buffer, tmp);
} // if

return buffer;
} // fatelf_get_target_string


void xfatelf_init(int argc, const char **argv)
{
memset(zerobuf, '\0', sizeof (zerobuf)); // just in case.
Expand Down

0 comments on commit e1488bd

Please sign in to comment.