sysprof r428 - trunk
- From: ssp svn gnome org
- To: svn-commits-list gnome org
- Subject: sysprof r428 - trunk
- Date: Mon, 2 Jun 2008 04:54:15 +0000 (UTC)
Author: ssp
Date: Mon Jun 2 04:54:15 2008
New Revision: 428
URL: http://svn.gnome.org/viewvc/sysprof?rev=428&view=rev
Log:
Mon Jun 2 00:51:46 2008 SÃren Sandmann <sandmann redhat com>
* binfile.c (get_debug_binaries): Keep a list of elf files for
each binary file. In some cases, notably glibc on Fedora, the
debug binary does not contain a symbol table, but the original
file does.
Modified:
trunk/ChangeLog
trunk/binfile.c
trunk/elfparser.c
trunk/elfparser.h
Modified: trunk/binfile.c
==============================================================================
--- trunk/binfile.c (original)
+++ trunk/binfile.c Mon Jun 2 04:54:15 2008
@@ -41,8 +41,8 @@
struct BinFile
{
int ref_count;
-
- ElfParser * elf;
+
+ GList * elf_files;
char * filename;
@@ -91,6 +91,62 @@
static const char *const debug_file_directory = DEBUGDIR;
static ElfParser *
+get_build_id_file (ElfParser *elf)
+{
+ const char *build_id;
+ GList *tries = NULL, *list;
+ char *init, *rest;
+ ElfParser *result = NULL;
+ char *tmp;
+
+ build_id = elf_parser_get_build_id (elf);
+
+ if (!build_id)
+ return NULL;
+
+ if (strlen (build_id) < 4)
+ return NULL;
+
+ init = g_strndup (build_id, 2);
+ rest = g_strdup_printf ("%s%s", build_id + 2, ".debug");
+
+ tmp = g_build_filename (
+ "/usr", "lib", "debug", ".build-id", init, rest, NULL);
+ tries = g_list_append (tries, tmp);
+
+ tmp = g_build_filename (
+ debug_file_directory, ".build-id", init, rest, NULL);
+ tries = g_list_append (tries, tmp);
+
+ for (list = tries; list != NULL; list = list->next)
+ {
+ char *name = list->data;
+ ElfParser *parser = elf_parser_new (name, NULL);
+
+ if (parser)
+ {
+ const char *file_id = elf_parser_get_build_id (parser);
+
+ if (file_id && strcmp (build_id, file_id) == 0)
+ {
+ result = parser;
+ break;
+ }
+
+ elf_parser_free (parser);
+ }
+ }
+
+ g_list_foreach (tries, (GFunc)g_free, NULL);
+ g_list_free (tries);
+
+ g_free (init);
+ g_free (rest);
+
+ return result;
+}
+
+static ElfParser *
get_debuglink_file (ElfParser *elf,
const char *filename,
char **new_name)
@@ -155,116 +211,51 @@
return result;
}
-static ElfParser *
-get_build_id_file (ElfParser *elf,
- const char *filename,
- char **new_name)
-{
- const char *build_id = elf_parser_get_build_id (elf);
- GList *tries = NULL, *list;
- char *init, *rest;
- ElfParser *result = NULL;
-
- if (!build_id)
- return NULL;
-
- if (strlen (build_id) < 4)
- return NULL;
-
- init = g_strndup (build_id, 2);
- rest = g_strdup_printf ("%s%s", build_id + 2, ".debug");
-
- tries = g_list_append (tries, g_build_filename ("/usr", "lib", "debug", ".build-id", init, rest, NULL));
- tries = g_list_append (tries, g_build_filename (debug_file_directory, ".build-id", init, rest, NULL));
-
- for (list = tries; list != NULL; list = list->next)
- {
- const char *name = list->data;
- ElfParser *parser = elf_parser_new (name, NULL);
-
- if (parser)
- {
- const char *file_id = elf_parser_get_build_id (parser);
-
- if (file_id && strcmp (build_id, file_id) == 0)
- {
- *new_name = g_strdup (name);
- result = parser;
- break;
- }
-
- elf_parser_free (parser);
- }
- }
-
- g_list_foreach (tries, (GFunc)g_free, NULL);
- g_list_free (tries);
-
- g_free (init);
- g_free (rest);
-
- return result;
-}
-
-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)
-{
- ElfParser *debug;
- char *debug_name = NULL;
- char *fname;
- GHashTable *seen_names =
- g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
- fname = g_strdup (filename);
+static GList *
+get_debug_binaries (GList *files,
+ ElfParser *elf,
+ const char *filename)
+{
+ ElfParser *build_id_file;
+ ElfParser *debuglink_file;
+ GHashTable *seen_names;
+ GList *free_us = NULL;
+
+ build_id_file = get_build_id_file (elf);
+
+ if (build_id_file)
+ return g_list_prepend (files, build_id_file);
+
+ /* .gnu_debuglink is actually a chain of debuglinks, and
+ * there have been cases where you'd have to follow it.
+ */
+ seen_names = g_hash_table_new (g_str_hash, g_str_equal);
do
{
- if (g_hash_table_lookup (seen_names, fname))
- {
-#if 0
- g_print (" cycle detected\n");
-#endif
- /* cycle detected, just return the original elf file itself */
+ char *debug_name;
+
+ if (g_hash_table_lookup (seen_names, filename))
break;
- }
-
- debug = get_debug_file (elf, fname, &debug_name);
+
+ g_hash_table_insert (seen_names, (char *)filename, (char *)filename);
- if (debug)
- {
- elf_parser_free (elf);
- elf = debug;
-
- g_hash_table_insert (seen_names, fname, fname);
- fname = debug_name;
- }
-#if 0
- else
+ debuglink_file = get_debuglink_file (elf, filename, &debug_name);
+
+ if (debuglink_file)
{
- g_print (" no debug info file for %s\n", fname);
+ free_us = g_list_prepend (free_us, debug_name);
+ files = g_list_prepend (files, debuglink_file);
+
+ filename = debug_name;
}
-#endif
}
- while (debug);
+ while (debuglink_file);
- g_free (fname);
- g_hash_table_destroy (seen_names);
-
- return elf;
+ g_list_foreach (free_us, (GFunc)g_free, NULL);
+ g_list_free (free_us);
+
+ return files;
}
static GHashTable *bin_files;
@@ -286,67 +277,43 @@
}
else
{
+ ElfParser *elf = NULL;
+
bf = g_new0 (BinFile, 1);
bf->inode_check = FALSE;
bf->filename = g_strdup (filename);
bf->undefined_name = g_strdup_printf ("In file %s", filename);
bf->ref_count = 1;
+ bf->elf_files = NULL;
g_hash_table_insert (bin_files, bf->filename, bf);
if (strcmp (filename, "[vdso]") == 0)
{
- gsize length;
const guint8 *vdso_bytes;
+ gsize length;
vdso_bytes = process_get_vdso_bytes (&length);
+
if (vdso_bytes)
- {
- bf->elf = elf_parser_new_from_data (vdso_bytes, length);
-#if 0
- g_print ("got vdso elf: %p (%d)\n", bf->elf, length);
-#endif
- }
- else
- bf->elf = NULL;
+ elf = elf_parser_new_from_data (vdso_bytes, length);
}
else
{
- bf->elf = elf_parser_new (filename, NULL);
-#if 0
- if (!bf->elf)
- g_print ("Could not parse file %s\n", filename);
-#endif
+ elf = elf_parser_new (filename, NULL);
}
-
- /* We need the text offset of the actual binary, not the
- * (potential) debug binary
- */
- if (bf->elf)
+
+ if (elf)
{
- ElfParser *oldelf;
-
- bf->text_offset = elf_parser_get_text_offset (bf->elf);
-#if 0
- g_print ("text offset: %d\n", bf->text_offset);
-#endif
+ /* We need the text offset of the actual binary, not the
+ * (potential) debug binaries
+ */
+ bf->text_offset = elf_parser_get_text_offset (elf);
- oldelf = bf->elf;
-#if 0
- if (bf->elf)
- g_print ("trying to find separate debug file for %s\n", filename);
-#endif
- bf->elf = find_separate_debug_file (bf->elf, filename);
+ bf->elf_files = get_debug_binaries (bf->elf_files, elf, filename);
+ bf->elf_files = g_list_append (bf->elf_files, elf);
-#if 0
- if (!bf->elf)
- g_print (" returned NULL\n");
- else if (bf->elf != oldelf)
- g_print (" successfully opened a different elf file than the original\n");
- else
- g_print (" opened the original elf file\n");
-#endif
bf->inode = read_inode (filename);
}
}
@@ -360,9 +327,9 @@
if (--bin_file->ref_count == 0)
{
g_hash_table_remove (bin_files, bin_file->filename);
-
- if (bin_file->elf)
- elf_parser_free (bin_file->elf);
+
+ g_list_foreach (bin_file->elf_files, (GFunc)elf_parser_free, NULL);
+ g_list_free (bin_file->elf_files);
g_free (bin_file->filename);
g_free (bin_file->undefined_name);
@@ -374,39 +341,40 @@
bin_file_lookup_symbol (BinFile *bin_file,
gulong address)
{
+ GList *list;
+
#if 0
g_print ("-=-=-=- \n");
-#endif
-
- if (bin_file->elf)
- {
-#if 0
- g_print ("bin file lookup lookup %d\n", address);
+
+ g_print ("bin file lookup lookup %d\n", address);
#endif
- address -= bin_file->text_offset;
-
+ address -= bin_file->text_offset;
+
#if 0
- g_print ("lookup %d in %s\n", address, bin_file->filename);
+ g_print ("lookup %d in %s\n", address, bin_file->filename);
#endif
- const ElfSym *sym = elf_parser_lookup_symbol (bin_file->elf, address);
+ for (list = bin_file->elf_files; list != NULL; list = list->next)
+ {
+ ElfParser *elf = list->data;
+ const ElfSym *sym = elf_parser_lookup_symbol (elf, address);
if (sym)
{
#if 0
- g_print ("found %lx => %s\n", address, bin_symbol_get_name (bin_file, sym));
+ g_print ("found %lx => %s\n", address,
+ bin_symbol_get_name (bin_file, sym));
#endif
return (const BinSymbol *)sym;
}
}
-#if 0
- else
- g_print ("no elf file for %s\n", bin_file->filename);
-#endif
#if 0
- g_print ("%lx undefined in %s (textoffset %x)\n", address + bin_file->text_offset, bin_file->filename, bin_file->text_offset);
+ g_print ("%lx undefined in %s (textoffset %x)\n",
+ address + bin_file->text_offset,
+ bin_file->filename,
+ bin_file->text_offset);
#endif
return (const BinSymbol *)bin_file->undefined_name;
@@ -419,7 +387,7 @@
if (bin_file->inode == inode)
return TRUE;
- if (!bin_file->elf)
+ if (!bin_file->elf_files)
return FALSE;
if (!bin_file->inode_check)
@@ -434,14 +402,48 @@
return FALSE;
}
+static const ElfSym *
+get_elf_sym (BinFile *file,
+ const BinSymbol *symbol,
+ ElfParser **elf_ret)
+{
+ GList *list;
+
+ for (list = file->elf_files; list != NULL; list = list->next)
+ {
+ const ElfSym *sym = (const ElfSym *)symbol;
+ ElfParser *elf = list->data;
+
+ if (elf_parser_owns_symbol (elf, sym))
+ {
+ *elf_ret = elf;
+ return sym;
+ }
+ }
+
+ g_critical ("Internal error: unrecognized symbol pointer");
+
+ *elf_ret = NULL;
+ return NULL;
+}
+
const char *
bin_symbol_get_name (BinFile *file,
const BinSymbol *symbol)
{
if (file->undefined_name == (char *)symbol)
+ {
return file->undefined_name;
+ }
else
- return elf_parser_get_sym_name (file->elf, (const ElfSym *)symbol);
+ {
+ ElfParser *elf;
+ const ElfSym *sym;
+
+ sym = get_elf_sym (file, symbol, &elf);
+
+ return elf_parser_get_sym_name (elf, sym);
+ }
}
gulong
@@ -449,7 +451,16 @@
const BinSymbol *symbol)
{
if (file->undefined_name == (char *)symbol)
+ {
return 0x0;
+ }
else
- return file->text_offset + elf_parser_get_sym_address (file->elf, (const ElfSym *)symbol);
+ {
+ ElfParser *elf;
+ const ElfSym *sym;
+
+ sym = get_elf_sym (file, symbol, &elf);
+
+ return elf_parser_get_sym_address (elf, sym);
+ }
}
Modified: trunk/elfparser.c
==============================================================================
--- trunk/elfparser.c (original)
+++ trunk/elfparser.c Mon Jun 2 04:54:15 2008
@@ -766,6 +766,21 @@
return result;
}
+gboolean
+elf_parser_owns_symbol (ElfParser *parser,
+ const ElfSym *sym)
+{
+ ElfSym *first, *last;
+
+ if (!parser->n_symbols)
+ return FALSE;
+
+ first = parser->symbols;
+ last = parser->symbols + parser->n_symbols - 1;
+
+ return first <= sym && sym <= last;
+}
+
gulong
elf_parser_get_sym_address (ElfParser *parser,
const ElfSym *sym)
Modified: trunk/elfparser.h
==============================================================================
--- trunk/elfparser.h (original)
+++ trunk/elfparser.h Mon Jun 2 04:54:15 2008
@@ -51,4 +51,6 @@
const ElfSym *sym);
gulong elf_parser_get_sym_address (ElfParser *parser,
const ElfSym *sym);
+gboolean elf_parser_owns_symbol (ElfParser *parser,
+ const ElfSym *sym);
char *elf_demangle (const char *name);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]