summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@src.gnome.org>2008-04-20 20:58:11 +0000
committerSøren Sandmann Pedersen <ssp@src.gnome.org>2008-04-20 20:58:11 +0000
commit90d1fa1de5b92650f8afce07fe84c56829425b5f (patch)
treee85fd954bdee49f40b9a61bb6d082ef9c3317ce4
parent12de20b938a28c309642180f84781e2e339a641c (diff)
Initial build id support
svn path=/trunk/; revision=410
-rw-r--r--ChangeLog4
-rw-r--r--TODO3
-rw-r--r--binfile.c27
-rw-r--r--binparser.c1
-rw-r--r--elfparser.c73
-rw-r--r--elfparser.h2
-rw-r--r--testelf.c15
7 files changed, 114 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index bd02365..08a796a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sun Apr 20 16:55:47 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * elfparser.c (elf_parser_new_from_data): Initial build-id support
+
2008-04-01 Owen Taylor <otaylor@redhat.com>
* sysprof.c (on_samples_label_size_request): Constrain the
diff --git a/TODO b/TODO
index 72e4f7f..f22ad1c 100644
--- a/TODO
+++ b/TODO
@@ -169,6 +169,9 @@ Before 1.2:
- "native endian" is probably not useful. Maybe go back to just
having big/little endian.
+ Should probably rethink the whole thing. It's just not very convenient to use, even
+ for simple things like ELF files.
+
* Rename stack_stash_foreach_by_address() to stack_stash_foreach_unique(),
or maybe not ...
diff --git a/binfile.c b/binfile.c
index 9315e98..d6ccab4 100644
--- a/binfile.c
+++ b/binfile.c
@@ -127,9 +127,9 @@ separate_debug_file_exists (const char *name, guint32 crc)
static const char *const debug_file_directory = DEBUGDIR;
static ElfParser *
-get_debug_file (ElfParser *elf,
- const char *filename,
- char **new_name)
+get_debuglink_file (ElfParser *elf,
+ const char *filename,
+ char **new_name)
{
#define N_TRIES 4
const char *basename;
@@ -184,6 +184,27 @@ get_debug_file (ElfParser *elf,
}
static ElfParser *
+get_build_id_file (ElfParser *elf,
+ const char *filename,
+ char **new_name)
+{
+ return NULL;
+}
+
+static ElfParser *
+get_debug_file (ElfParser *elf,
+ const char *filename,
+ char **new_name)
+{
+ ElfParser *t;
+
+ if ((t = get_build_id_file (elf, filename, new_name)))
+ return t;
+ else
+ return get_debuglink_file (elf, filename, new_name);
+}
+
+static ElfParser *
find_separate_debug_file (ElfParser *elf,
const char *filename)
{
diff --git a/binparser.c b/binparser.c
index 0a24981..152315f 100644
--- a/binparser.c
+++ b/binparser.c
@@ -324,7 +324,6 @@ bin_parser_get_string (BinParser *parser)
parser->offset += strlen (result) + 1;
return result;
-
}
static const Field *
diff --git a/elfparser.c b/elfparser.c
index 5224618..b404eca 100644
--- a/elfparser.c
+++ b/elfparser.c
@@ -48,6 +48,7 @@ struct ElfParser
BinRecord * strtab_format;
BinRecord * shn_entry;
BinRecord * sym_format;
+ BinRecord * note_format;
int n_sections;
Section ** sections;
@@ -59,6 +60,9 @@ struct ElfParser
GMappedFile * file;
char * filename;
+
+ gboolean checked_build_id;
+ char * build_id;
const Section * text_section;
};
@@ -217,6 +221,7 @@ elf_parser_new_from_data (const guchar *data,
parser->text_section = find_section (parser, ".text", SHT_NOBITS);
parser->filename = NULL;
+ parser->build_id = NULL;
return parser;
}
@@ -365,6 +370,9 @@ elf_parser_free (ElfParser *parser)
if (parser->filename)
g_free (parser->filename);
+
+ if (parser->build_id)
+ g_free (parser->build_id);
g_free (parser);
}
@@ -468,7 +476,7 @@ read_table (ElfParser *parser,
parser->symbols[n_functions].offset = offset;
n_functions++;
-
+
#if 0
g_print (" symbol: %s: %lx\n",
get_string_indirect (parser->parser,
@@ -634,6 +642,53 @@ elf_parser_get_text_offset (ElfParser *parser)
return parser->text_section->offset;
}
+const gchar *
+elf_parser_get_build_id (ElfParser *parser)
+{
+ if (!parser->checked_build_id)
+ {
+ const Section *build_id = find_section (parser, ".note.gnu.build-id", SHT_NOTE);
+ guint64 name_size;
+ guint64 desc_size;
+ guint64 type;
+ const char *name;
+ const char *desc;
+ GString *string;
+ int i;
+ const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ parser->checked_build_id = TRUE;
+
+ if (!build_id)
+ return NULL;
+
+ bin_parser_set_offset (parser->parser, build_id->offset);
+
+ name_size = bin_parser_get_uint_field (parser->parser, parser->note_format, "name_size");
+ desc_size = bin_parser_get_uint_field (parser->parser, parser->note_format, "desc_size");
+ type = bin_parser_get_uint_field (parser->parser, parser->note_format, "type");
+
+ name = bin_parser_get_string (parser->parser);
+
+ bin_parser_align (parser->parser, 4);
+
+ desc = bin_parser_get_string (parser->parser);
+
+ string = g_string_new (NULL);
+
+ for (i = 0; i < desc_size; ++i)
+ {
+ g_string_append_c (string, hex_digits[desc[i] & 0xf0]);
+ g_string_append_c (string, hex_digits[desc[i] & 0x0f]);
+ }
+
+ parser->build_id = g_string_free (string, FALSE);
+ }
+
+ return parser->build_id;
+}
+
const char *
elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
{
@@ -745,7 +800,8 @@ static void
get_formats (gboolean is_64,
const BinField **elf_header,
const BinField **shn_entry,
- const BinField **sym_format)
+ const BinField **sym_format,
+ const BinField **note_format_out)
{
static const BinField elf64_header[] = {
{ "e_ident", BIN_UNINTERPRETED, EI_NIDENT },
@@ -831,6 +887,12 @@ get_formats (gboolean is_64,
{ "" },
};
+ static const BinField note_format[] = {
+ { "name_size", BIN_UINT, 4 },
+ { "desc_size", BIN_UINT, 4 },
+ { "type", BIN_UINT, 4 },
+ };
+
if (is_64)
{
*elf_header = elf64_header;
@@ -843,17 +905,20 @@ get_formats (gboolean is_64,
*shn_entry = shn32_entry;
*sym_format = sym32_format;
}
+
+ *note_format_out = note_format;
}
static void
make_formats (ElfParser *parser, gboolean is_64)
{
- const BinField *elf_header, *shn_entry, *sym_format;
+ const BinField *elf_header, *shn_entry, *sym_format, *note_format;
- get_formats (is_64, &elf_header, &shn_entry, &sym_format);
+ get_formats (is_64, &elf_header, &shn_entry, &sym_format, &note_format);
parser->header = bin_parser_create_record (parser->parser, elf_header);
parser->shn_entry = bin_parser_create_record (parser->parser, shn_entry);
parser->sym_format = bin_parser_create_record (parser->parser, sym_format);
+ parser->note_format = bin_parser_create_record (parser->parser, note_format);
}
diff --git a/elfparser.h b/elfparser.h
index 10ba62b..842f85c 100644
--- a/elfparser.h
+++ b/elfparser.h
@@ -27,11 +27,11 @@ ElfParser * elf_parser_new (const char *filename,
void elf_parser_free (ElfParser *parser);
const char * elf_parser_get_debug_link (ElfParser *parser,
guint32 *crc32);
+const gchar *elf_parser_get_build_id (ElfParser *parser);
const guchar *elf_parser_get_eh_frame (ElfParser *parser);
const guchar *elf_parser_get_debug_frame (ElfParser *parser);
gulong elf_parser_get_text_offset (ElfParser *parser);
-
/* Lookup a symbol in the file.
*
* The symbol returned is const, so don't free it it or anything. It
diff --git a/testelf.c b/testelf.c
index ed2c7a8..9a96e80 100644
--- a/testelf.c
+++ b/testelf.c
@@ -31,12 +31,19 @@ check (ElfParser *elf, gulong addr)
}
int
-main ()
+main (int argc, char **argv)
{
ElfParser *elf;
int i;
+ const char *build_id;
+ const char *filename;
- elf = elf_parser_new ("/usr/lib/libgtk-x11-2.0.so", NULL);
+ if (argc == 1)
+ filename = "/usr/lib/libgtk-x11-2.0.so";
+ else
+ filename = argv[0];
+
+ elf = elf_parser_new (filename, NULL);
if (!elf)
{
@@ -44,6 +51,10 @@ main ()
return -1;
}
+ build_id = elf_parser_get_build_id (elf);
+
+ g_print ("build ID: %s\n", build_id);
+
elf_parser_get_crc32 (elf);
for (i = 0; i < 5000000; ++i)