summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2007-12-06 14:21:47 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2007-12-06 15:06:50 +0000
commitf0a0555723491e4246ec07136f443daea2b55bba (patch)
tree1443a0e07dbc0bb35eb81e92647bfc8f8e949547
parent6934720f91c82666e6437792ffb34eaa08ea65da (diff)
Eliminate the strcmp entirely for field lookup.
-rw-r--r--src/minibfd/binparser.c65
-rw-r--r--src/minibfd/binparser.h43
-rw-r--r--src/minibfd/elfparser.c219
3 files changed, 151 insertions, 176 deletions
diff --git a/src/minibfd/binparser.c b/src/minibfd/binparser.c
index 352a0b6..44bf0a6 100644
--- a/src/minibfd/binparser.c
+++ b/src/minibfd/binparser.c
@@ -26,7 +26,6 @@
typedef struct _field Field;
struct _field {
- char name[BIN_MAX_NAME];
guint offset; /* from beginning of struct */
guint width;
BinType type;
@@ -72,21 +71,8 @@ bin_parser_get_length (BinParser *parser)
return parser->length;
}
-static guint64
-align (guint64 offset, int alignment)
-{
- /* Note that we can speed this up by assuming alignment'
- * is a power of two, since
- *
- * offset % alignment == offset & (alignemnt - 1)
- *
- */
-
- if (offset % alignment != 0)
- offset += (alignment - (offset % alignment));
-
- return offset;
-}
+#define align(offset__, alignment__) \
+ ((offset__ + alignment__ - 1) &~ (alignment__ - 1))
static int
get_align (const BinField *field)
@@ -97,22 +83,15 @@ get_align (const BinField *field)
return field->n_bytes;
}
-static int
-field_strcmp (const void *A, const void *B)
-{
- const Field *a = A, *b = B;
- return strcmp (a->name, b->name);
-}
-
BinRecord *
bin_parser_create_record (BinParser *parser, const BinField *fields)
{
BinRecord *record;
- int i, n_fields;
+ guint i, n_fields;
guint offset;
n_fields = 0;
- while (fields[n_fields].name[0] != '\0')
+ while (fields[n_fields].index != -1)
n_fields++;
record = g_malloc (sizeof (BinRecord) + n_fields * sizeof (Field));
@@ -121,23 +100,19 @@ bin_parser_create_record (BinParser *parser, const BinField *fields)
record->n_fields = n_fields;
for (i = 0; i < n_fields; ++i) {
const BinField *bin_field = &fields[i];
- Field *field = &record->fields[i];
+ Field *field;
offset = align (offset, get_align (bin_field));
- strncpy (field->name, bin_field->name, BIN_MAX_NAME - 1);
+ field = &record->fields[bin_field->index];
field->offset = offset;
field->type = bin_field->type;
field->width = bin_field->n_bytes;
- offset += record->fields[i].width;
+ offset += field->width;
}
- record->size = align (record->fields[n_fields-1].offset +
- record->fields[n_fields-1].width,
- record->fields[0].width);
-
- qsort (record->fields, n_fields, sizeof (Field), field_strcmp);
+ record->size = align (offset, get_align (fields));
record->next = parser->records;
parser->records = record;
@@ -295,35 +270,15 @@ bin_parser_get_string (BinParser *parser)
}
-static const Field *
-get_field (BinRecord *format, const gchar *name)
-{
- guint first = 0, last = format->n_fields;
- while (last - first > 1) {
- gint cmp;
- guint mid = (first + last) / 2;
- cmp = strcmp (name, format->fields[mid].name);
- if (cmp < 0)
- last = mid;
- else if (cmp > 0)
- first = mid;
- else
- return &format->fields[mid];
-
- }
- return &format->fields[first];
-}
-
guint64
bin_parser_get_uint_field (BinParser *parser,
BinRecord *record,
- const char *name)
+ int field_ident)
{
- const Field *field = get_field (record, name);
+ const Field *field = &record->fields[field_ident];
const guchar *pos;
pos = parser->data + parser->offset + field->offset;
-
if (pos > parser->data + parser->length) {
/* FIXME: generate error */
return 0;
diff --git a/src/minibfd/binparser.h b/src/minibfd/binparser.h
index 68c32da..ea84afe 100644
--- a/src/minibfd/binparser.h
+++ b/src/minibfd/binparser.h
@@ -58,8 +58,6 @@ typedef struct _bin_field BinField;
*
*/
-#define BIN_MAX_NAME 52
-
typedef enum {
BIN_LITTLE_ENDIAN,
BIN_BIG_ENDIAN,
@@ -73,7 +71,7 @@ typedef enum {
} BinType;
struct _bin_field {
- const char name[BIN_MAX_NAME];
+ short index;
char type;
char n_bytes; /* number of bytes in the type */
};
@@ -105,12 +103,49 @@ gboolean bin_parser_error (BinParser *parser);
void bin_parser_clear_error (BinParser *parser);
const gchar * bin_parser_get_error_msg (BinParser *parser);
+/* field idents */
+enum {
+ e_ident = 0,
+ e_type,
+ e_machine,
+ e_version,
+ e_entry,
+ e_phoff,
+ e_shoff,
+ e_flags,
+ e_ehsize,
+ e_phentsize,
+ e_phnum,
+ e_shentsize,
+ e_shnum,
+ e_shstrndx
+};
+enum {
+ sh_name = 0,
+ sh_type,
+ sh_flags,
+ sh_addr,
+ sh_offset,
+ sh_size,
+ sh_link,
+ sh_info,
+ sh_addralign,
+ sh_entsize
+};
+enum {
+ st_name = 0,
+ st_info,
+ st_other,
+ st_shndx,
+ st_value,
+ st_size
+};
BinRecord * bin_parser_create_record (BinParser *parser,
const BinField *fields);
gsize bin_record_get_size (BinRecord *record);
guint64 bin_parser_get_uint_field (BinParser *parser,
BinRecord *record,
- const char *field);
+ int field_ident);
/* Move current offset */
gsize bin_parser_get_offset (BinParser *parser);
diff --git a/src/minibfd/elfparser.c b/src/minibfd/elfparser.c
index 6b174e2..2ae1660 100644
--- a/src/minibfd/elfparser.c
+++ b/src/minibfd/elfparser.c
@@ -69,14 +69,14 @@ get_formats (gboolean is_64,
static const char *
get_string_indirect (BinParser *parser,
BinRecord *record,
- const char *name,
+ int field_ident,
gsize str_table)
{
const char *result = NULL;
gsize index;
bin_parser_save (parser); {
- index = bin_parser_get_uint_field (parser, record, name);
+ index = bin_parser_get_uint_field (parser, record, field_ident);
bin_parser_set_offset (parser, str_table + index);
@@ -94,20 +94,20 @@ section_init (Section *section,
{
guint64 flags;
- section->name = get_string_indirect (parser, record, "sh_name", name_table);
- section->size = bin_parser_get_uint_field (parser, record, "sh_size");
- section->offset = bin_parser_get_uint_field (parser, record, "sh_offset");
+ section->name = get_string_indirect (parser, record, sh_name, name_table);
+ section->size = bin_parser_get_uint_field (parser, record, sh_size);
+ section->offset = bin_parser_get_uint_field (parser, record, sh_offset);
- flags = bin_parser_get_uint_field (parser, record, "sh_flags");
+ flags = bin_parser_get_uint_field (parser, record, sh_flags);
section->allocated = !!(flags & SHF_ALLOC);
if (section->allocated) {
section->load_address = bin_parser_get_uint_field (
- parser, record, "sh_addr");
+ parser, record, sh_addr);
} else
section->load_address = 0;
- section->type = bin_parser_get_uint_field (parser, record, "sh_type");
+ section->type = bin_parser_get_uint_field (parser, record, sh_type);
}
static const Section *
@@ -154,9 +154,7 @@ elf_parser_new_from_data (const guchar *data, gsize length)
header = bin_parser_create_record (&bin_parser, elf_header);
bin_parser_set_offset (&bin_parser, 0);
- n_sections = bin_parser_get_uint_field (&bin_parser,
- header,
- "e_shnum");
+ n_sections = bin_parser_get_uint_field (&bin_parser, header, e_shnum);
parser = g_malloc (sizeof (ElfParser) + sizeof (Section) * n_sections);
parser->parser = bin_parser;
@@ -170,10 +168,10 @@ elf_parser_new_from_data (const guchar *data, gsize length)
/* Read section headers */
section_names_idx = bin_parser_get_uint_field (&bin_parser,
header,
- "e_shstrndx");
+ e_shstrndx);
section_headers = bin_parser_get_uint_field (&bin_parser,
header,
- "e_shoff");
+ e_shoff);
bin_parser_set_offset (&bin_parser, section_headers);
bin_parser_save (&bin_parser); {
@@ -183,7 +181,7 @@ elf_parser_new_from_data (const guchar *data, gsize length)
section_names = bin_parser_get_uint_field (&bin_parser,
parser->shn_entry,
- "sh_offset");
+ sh_offset);
} bin_parser_restore (&bin_parser);
parser->n_sections = n_sections;
@@ -357,9 +355,9 @@ read_table (ElfParser *parser,
gulong offset;
info = bin_parser_get_uint_field (
- &parser->parser, parser->sym_format, "st_info");
+ &parser->parser, parser->sym_format, st_info);
addr = bin_parser_get_uint_field (
- &parser->parser, parser->sym_format, "st_value");
+ &parser->parser, parser->sym_format, st_value);
offset = bin_parser_get_offset (&parser->parser);
if (addr != 0 &&
@@ -370,9 +368,7 @@ read_table (ElfParser *parser,
{
parser->symbols[n_functions].address = addr;
parser->symbols[n_functions].offset = offset;
-
n_functions++;
-
}
bin_parser_seek_record (&parser->parser, parser->sym_format, 1);
@@ -388,21 +384,21 @@ read_table (ElfParser *parser,
static void
read_symbols (ElfParser *parser)
{
- const Section *symtab = find_section (parser, ".symtab", SHT_SYMTAB);
- const Section *strtab = find_section (parser, ".strtab", SHT_STRTAB);
- const Section *dynsym = find_section (parser, ".dynsym", SHT_DYNSYM);
- const Section *dynstr = find_section (parser, ".dynstr", SHT_STRTAB);
+ const Section *symtab, *strtab;
- if (symtab && strtab) {
- read_table (parser, symtab, strtab);
- }
- else if (dynsym && dynstr) {
- read_table (parser, dynsym, dynstr);
- } else {
- /* To make sure parser->symbols is non-NULL */
- parser->n_symbols = 0;
- parser->symbols = g_new (ElfSym, 1);
- }
+ symtab = find_section (parser, ".symtab", SHT_SYMTAB);
+ strtab = find_section (parser, ".strtab", SHT_STRTAB);
+ if (symtab != NULL && strtab != NULL)
+ return read_table (parser, symtab, strtab);
+
+ symtab = find_section (parser, ".dynsym", SHT_SYMTAB);
+ strtab = find_section (parser, ".dynstr", SHT_STRTAB);
+ if (symtab != NULL && strtab != NULL)
+ return read_table (parser, symtab, strtab);
+
+ /* To make sure parser->symbols is non-NULL */
+ parser->n_symbols = 0;
+ parser->symbols = g_new (ElfSym, 1);
}
static ElfSym *
@@ -410,11 +406,11 @@ do_lookup (ElfSym *symbols, gulong address, int first, int last)
{
do {
if (address >= symbols[last].address) {
- return &(symbols[last]);
+ return &symbols[last];
} else if (last - first < 3) {
while (last >= first) {
if (address >= symbols[last].address)
- return &(symbols[last]);
+ return &symbols[last];
last--;
}
@@ -432,8 +428,7 @@ do_lookup (ElfSym *symbols, gulong address, int first, int last)
/* Address should be given in 'offset into text segment' */
const ElfSym *
-elf_parser_lookup_symbol (ElfParser *parser,
- gulong address)
+elf_parser_lookup_symbol (ElfParser *parser, gulong address)
{
const ElfSym *result;
@@ -448,15 +443,13 @@ elf_parser_lookup_symbol (ElfParser *parser,
address += parser->text_section->load_address;
result = do_lookup (parser->symbols, address, 0, parser->n_symbols - 1);
-
if (result) {
gulong size;
bin_parser_set_offset (&parser->parser, result->offset);
size = bin_parser_get_uint_field (
- &parser->parser, parser->sym_format, "st_size");
-
+ &parser->parser, parser->sym_format, st_size);
if (size > 0 && result->address + size <= address)
result = NULL;
}
@@ -518,7 +511,7 @@ elf_parser_get_sym_name (ElfParser *parser, const ElfSym *sym)
bin_parser_set_offset (&parser->parser, sym->offset);
result = get_string_indirect (&parser->parser, parser->sym_format,
- "st_name", parser->sym_strings);
+ st_name, parser->sym_strings);
return result;
}
@@ -539,22 +532,17 @@ parse_elf_signature (const guchar *data,
gboolean *is_be)
{
/* FIXME: this function should be able to return an error */
- if (length < EI_NIDENT)
- {
+ if (length < EI_NIDENT) {
/* FIXME set error */
return FALSE;
}
- if (data[EI_CLASS] != ELFCLASS32 &&
- data[EI_CLASS] != ELFCLASS64)
- {
+ if (data[EI_CLASS] != ELFCLASS32 && data[EI_CLASS] != ELFCLASS64) {
/* FIXME set error */
return FALSE;
}
- if (data[EI_DATA] != ELFDATA2LSB &&
- data[EI_DATA] != ELFDATA2MSB)
- {
+ if (data[EI_DATA] != ELFDATA2LSB && data[EI_DATA] != ELFDATA2MSB) {
/* FIXME set error */
return FALSE;
}
@@ -575,87 +563,84 @@ get_formats (gboolean is_64,
const BinField **sym_format)
{
static const BinField elf64_header[] = {
- { "e_ident", BIN_UNINTERPRETED, EI_NIDENT },
- { "e_type", BIN_UINT, 2 },
- { "e_machine", BIN_UINT, 2 },
- { "e_version", BIN_UINT, 4 },
- { "e_entry", BIN_UINT, 8 },
- { "e_phoff", BIN_UINT, 8 },
- { "e_shoff", BIN_UINT, 8 },
- { "e_flags", BIN_UINT, 4 },
- { "e_ehsize", BIN_UINT, 2 },
- { "e_phentsize", BIN_UINT, 2 },
- { "e_phnum", BIN_UINT, 2 },
- { "e_shentsize", BIN_UINT, 2 },
- { "e_shnum", BIN_UINT, 2 },
- { "e_shstrndx", BIN_UINT, 2 },
- { "" },
+ { e_ident, BIN_UNINTERPRETED, EI_NIDENT },
+ { e_type, BIN_UINT, 2 },
+ { e_machine, BIN_UINT, 2 },
+ { e_version, BIN_UINT, 4 },
+ { e_entry, BIN_UINT, 8 },
+ { e_phoff, BIN_UINT, 8 },
+ { e_shoff, BIN_UINT, 8 },
+ { e_flags, BIN_UINT, 4 },
+ { e_ehsize, BIN_UINT, 2 },
+ { e_phentsize, BIN_UINT, 2 },
+ { e_phnum, BIN_UINT, 2 },
+ { e_shentsize, BIN_UINT, 2 },
+ { e_shnum, BIN_UINT, 2 },
+ { e_shstrndx, BIN_UINT, 2 },
+ { -1 },
};
-
static const BinField elf32_header[] = {
- { "e_ident", BIN_UNINTERPRETED, EI_NIDENT },
- { "e_type", BIN_UINT, 2 },
- { "e_machine", BIN_UINT, 2 },
- { "e_version", BIN_UINT, 4 },
- { "e_entry", BIN_UINT, 4 },
- { "e_phoff", BIN_UINT, 4 },
- { "e_shoff", BIN_UINT, 4 },
- { "e_flags", BIN_UINT, 4 },
- { "e_ehsize", BIN_UINT, 2 },
- { "e_phentsize", BIN_UINT, 2 },
- { "e_phnum", BIN_UINT, 2 },
- { "e_shentsize", BIN_UINT, 2 },
- { "e_shnum", BIN_UINT, 2 },
- { "e_shstrndx", BIN_UINT, 2 },
- { "" },
+ { e_ident, BIN_UNINTERPRETED, EI_NIDENT },
+ { e_type, BIN_UINT, 2 },
+ { e_machine, BIN_UINT, 2 },
+ { e_version, BIN_UINT, 4 },
+ { e_entry, BIN_UINT, 4 },
+ { e_phoff, BIN_UINT, 4 },
+ { e_shoff, BIN_UINT, 4 },
+ { e_flags, BIN_UINT, 4 },
+ { e_ehsize, BIN_UINT, 2 },
+ { e_phentsize, BIN_UINT, 2 },
+ { e_phnum, BIN_UINT, 2 },
+ { e_shentsize, BIN_UINT, 2 },
+ { e_shnum, BIN_UINT, 2 },
+ { e_shstrndx, BIN_UINT, 2 },
+ { -1 },
};
static const BinField shn64_entry[] = {
- { "sh_name", BIN_UINT, 4 },
- { "sh_type", BIN_UINT, 4 },
- { "sh_flags", BIN_UINT, 8 },
- { "sh_addr", BIN_UINT, 8 },
- { "sh_offset", BIN_UINT, 8 },
- { "sh_size", BIN_UINT, 8 },
- { "sh_link", BIN_UINT, 4 },
- { "sh_info", BIN_UINT, 4 },
- { "sh_addralign", BIN_UINT, 8 },
- { "sh_entsize", BIN_UINT, 8 },
- { "" }
+ { sh_name, BIN_UINT, 4 },
+ { sh_type, BIN_UINT, 4 },
+ { sh_flags, BIN_UINT, 8 },
+ { sh_addr, BIN_UINT, 8 },
+ { sh_offset, BIN_UINT, 8 },
+ { sh_size, BIN_UINT, 8 },
+ { sh_link, BIN_UINT, 4 },
+ { sh_info, BIN_UINT, 4 },
+ { sh_addralign, BIN_UINT, 8 },
+ { sh_entsize, BIN_UINT, 8 },
+ { -1 }
};
-
static const BinField shn32_entry[] = {
- { "sh_name", BIN_UINT, 4 },
- { "sh_type", BIN_UINT, 4 },
- { "sh_flags", BIN_UINT, 4 },
- { "sh_addr", BIN_UINT, 4 },
- { "sh_offset", BIN_UINT, 4 },
- { "sh_size", BIN_UINT, 4 },
- { "sh_link", BIN_UINT, 4 },
- { "sh_info", BIN_UINT, 4 },
- { "sh_addralign", BIN_UINT, 4 },
- { "sh_entsize", BIN_UINT, 4 },
- { "" }
+ { sh_name, BIN_UINT, 4 },
+ { sh_type, BIN_UINT, 4 },
+ { sh_flags, BIN_UINT, 4 },
+ { sh_addr, BIN_UINT, 4 },
+ { sh_offset, BIN_UINT, 4 },
+ { sh_size, BIN_UINT, 4 },
+ { sh_link, BIN_UINT, 4 },
+ { sh_info, BIN_UINT, 4 },
+ { sh_addralign, BIN_UINT, 4 },
+ { sh_entsize, BIN_UINT, 4 },
+ { -1 }
};
static const BinField sym64_format[] = {
- { "st_name", BIN_UINT, 4 },
- { "st_info", BIN_UINT, 1 },
- { "st_other", BIN_UINT, 1 },
- { "st_shndx", BIN_UINT, 2 },
- { "st_value", BIN_UINT, 8 },
- { "st_size", BIN_UINT, 8 },
- { "" }
+ { st_name, BIN_UINT, 4 },
+ { st_info, BIN_UINT, 1 },
+ { st_other, BIN_UINT, 1 },
+ { st_shndx, BIN_UINT, 2 },
+ { st_value, BIN_UINT, 8 },
+ { st_size, BIN_UINT, 8 },
+ { -1 }
};
-
static const BinField sym32_format[] = {
- { "st_name", BIN_UINT, 4 },
- { "st_value", BIN_UINT, 4 },
- { "st_size", BIN_UINT, 4 },
- { "st_info", BIN_UINT, 1 },
- { "st_other", BIN_UINT, 1 },
- { "st_shndx", BIN_UINT, 2 },
- { "" },
+ { st_name, BIN_UINT, 4 },
+ { st_value, BIN_UINT, 4 },
+ { st_size, BIN_UINT, 4 },
+ { st_info, BIN_UINT, 1 },
+ { st_other, BIN_UINT, 1 },
+ { st_shndx, BIN_UINT, 2 },
+ { -1 },
};
if (is_64) {