callgraph: teach callgraph to use alternative symbol roots

This allows us to have a sysroot different than /, so that we can resolve
symbols that are not necessarily installed on the system. For example, if
we are running an application in an alternate mount namespace, we will want
to resolve the symbols starting from the location of the checkout for that
namespace.

Generally alternate mount namespaces will have paths like "/newroot/usr/.."
so by setting the source to "/newroot/usr/" to "~/.local/" you can do
some fancy remapping.
This commit is contained in:
Christian Hergert
2017-02-25 19:34:58 -08:00
parent 9839869d98
commit 222d0ad53f
4 changed files with 114 additions and 10 deletions

View File

@ -24,6 +24,13 @@
#include "sp-map-lookaside.h"
#include "sp-elf-symbol-resolver.h"
typedef struct
{
gchar *src;
gchar *dst;
gsize srclen;
} SymbolDir;
struct _SpElfSymbolResolver
{
GObject parent_instance;
@ -31,6 +38,7 @@ struct _SpElfSymbolResolver
GHashTable *lookasides;
GHashTable *bin_files;
GHashTable *tag_cache;
GArray *symbol_dirs;
};
static void symbol_resolver_iface_init (SpSymbolResolverInterface *iface);
@ -50,6 +58,7 @@ sp_elf_symbol_resolver_finalize (GObject *object)
g_clear_pointer (&self->bin_files, g_hash_table_unref);
g_clear_pointer (&self->lookasides, g_hash_table_unref);
g_clear_pointer (&self->tag_cache, g_hash_table_unref);
g_clear_pointer (&self->symbol_dirs, g_array_unref);
G_OBJECT_CLASS (sp_elf_symbol_resolver_parent_class)->finalize (object);
}
@ -65,6 +74,8 @@ sp_elf_symbol_resolver_class_init (SpElfSymbolResolverClass *klass)
static void
sp_elf_symbol_resolver_init (SpElfSymbolResolver *self)
{
self->symbol_dirs = g_array_new (FALSE, FALSE, sizeof (SymbolDir));
self->lookasides = g_hash_table_new_full (NULL,
NULL,
NULL,
@ -131,11 +142,30 @@ sp_elf_symbol_resolver_get_bin_file (SpElfSymbolResolver *self,
g_assert (SP_IS_ELF_SYMBOL_RESOLVER (self));
if (filename == NULL)
return NULL;
bin_file = g_hash_table_lookup (self->bin_files, filename);
if (bin_file == NULL)
{
bin_file = bin_file_new (filename);
g_autofree gchar *translated = NULL;
const gchar *alternate = filename;
/*
* See if we have a symbol directory that is set to be the resolution
* path for this filename. We will want to alter where we find the
* symbols based on this directory.
*/
for (guint i = 0; i < self->symbol_dirs->len; i++)
{
const SymbolDir *sd = &g_array_index (self->symbol_dirs, SymbolDir, i);
if (g_str_has_prefix (filename, sd->src))
alternate = translated = g_build_filename (sd->dst, filename + sd->srclen, NULL);
}
bin_file = bin_file_new (alternate);
g_hash_table_insert (self->bin_files, g_strdup (filename), bin_file);
}
@ -292,3 +322,33 @@ sp_elf_symbol_resolver_new (void)
{
return g_object_new (SP_TYPE_ELF_SYMBOL_RESOLVER, NULL);
}
void
sp_elf_symbol_resolver_set_symbol_dirs (SpElfSymbolResolver *self,
GHashTable *symbol_dirs)
{
GHashTableIter iter;
g_return_if_fail (SP_IS_ELF_SYMBOL_RESOLVER (self));
if (self->symbol_dirs->len)
g_array_remove_range (self->symbol_dirs, 0, self->symbol_dirs->len - 1);
if (symbol_dirs)
{
gpointer k, v;
g_hash_table_iter_init (&iter, symbol_dirs);
while (g_hash_table_iter_next (&iter, &k, &v))
{
SymbolDir dir;
dir.src = g_strdup ((gchar *)k);
dir.srclen = strlen (dir.src);
dir.dst = g_strdup ((gchar *)v);
g_array_append_val (self->symbol_dirs, dir);
}
}
}