libsysprof-analyze: use mountnamespace/addresslayout in symbolize

This commit is contained in:
Christian Hergert
2023-05-10 16:51:05 -07:00
parent c72955e7d4
commit 8f4fa95663
7 changed files with 97 additions and 113 deletions

View File

@ -169,10 +169,11 @@ search_for_symbol_cb (gconstpointer a,
} }
static SysprofSymbol * static SysprofSymbol *
sysprof_bundled_symbolizer_symbolize (SysprofSymbolizer *symbolizer, sysprof_bundled_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
gint64 time, SysprofMountNamespace *mount_namespace,
int pid, SysprofAddressLayout *address_layout,
SysprofAddress address) int pid,
SysprofAddress address)
{ {
SysprofBundledSymbolizer *self = SYSPROF_BUNDLED_SYMBOLIZER (symbolizer); SysprofBundledSymbolizer *self = SYSPROF_BUNDLED_SYMBOLIZER (symbolizer);
g_autoptr(GRefString) tag = NULL; g_autoptr(GRefString) tag = NULL;

View File

@ -27,6 +27,8 @@ G_BEGIN_DECLS
void _sysprof_document_symbols_new (SysprofDocument *document, void _sysprof_document_symbols_new (SysprofDocument *document,
SysprofSymbolizer *symbolizer, SysprofSymbolizer *symbolizer,
GHashTable *pid_to_mount_namespaces,
GHashTable *pid_to_address_layouts,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);

View File

@ -20,9 +20,11 @@
#include "config.h" #include "config.h"
#include "sysprof-address-layout-private.h"
#include "sysprof-document-private.h" #include "sysprof-document-private.h"
#include "sysprof-document-symbols-private.h" #include "sysprof-document-symbols-private.h"
#include "sysprof-document-traceable.h" #include "sysprof-document-traceable.h"
#include "sysprof-mount-namespace-private.h"
#include "sysprof-symbol-private.h" #include "sysprof-symbol-private.h"
#include "sysprof-symbol-cache-private.h" #include "sysprof-symbol-cache-private.h"
#include "sysprof-symbolizer-private.h" #include "sysprof-symbolizer-private.h"
@ -68,6 +70,8 @@ typedef struct _Symbolize
SysprofDocument *document; SysprofDocument *document;
SysprofSymbolizer *symbolizer; SysprofSymbolizer *symbolizer;
SysprofDocumentSymbols *symbols; SysprofDocumentSymbols *symbols;
GHashTable *pid_to_address_layouts;
GHashTable *pid_to_mount_namespaces;
} Symbolize; } Symbolize;
static void static void
@ -76,48 +80,29 @@ symbolize_free (Symbolize *state)
g_clear_object (&state->document); g_clear_object (&state->document);
g_clear_object (&state->symbolizer); g_clear_object (&state->symbolizer);
g_clear_object (&state->symbols); g_clear_object (&state->symbols);
g_clear_pointer (&state->pid_to_address_layouts, g_hash_table_unref);
g_clear_pointer (&state->pid_to_mount_namespaces, g_hash_table_unref);
g_free (state); g_free (state);
} }
static void static void
sysprof_document_symbols_add_traceable (SysprofDocumentSymbols *self, sysprof_document_symbols_add_traceable (SysprofDocumentSymbols *self,
SysprofDocumentTraceable *traceable, SysprofDocumentTraceable *traceable,
SysprofSymbolizer *symbolizer) SysprofSymbolizer *symbolizer,
SysprofMountNamespace *mount_namespace,
SysprofAddressLayout *address_layout,
SysprofSymbolCache *symbol_cache)
{ {
SysprofAddressContext last_context; SysprofAddressContext last_context;
SysprofSymbolCache *symbol_cache;
guint64 *addresses; guint64 *addresses;
guint n_addresses; guint n_addresses;
gint64 time;
int pid; int pid;
g_assert (SYSPROF_IS_DOCUMENT_SYMBOLS (self)); g_assert (SYSPROF_IS_DOCUMENT_SYMBOLS (self));
g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable)); g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable));
g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer)); g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer));
time = sysprof_document_frame_get_time (SYSPROF_DOCUMENT_FRAME (traceable));
pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable));
if (!(symbol_cache = g_hash_table_lookup (self->pid_to_symbol_cache, GINT_TO_POINTER (pid))))
{
symbol_cache = sysprof_symbol_cache_new ();
g_hash_table_insert (self->pid_to_symbol_cache, GINT_TO_POINTER (pid), symbol_cache);
}
/* TODO: We need to get the SysprofMountNamespace for the PID which must have
* already been compiled. We also need the list SysprofDocumentMmap so that we
* can get the build-id or inode to do various validation checks.
*
* It would be nice if that was all pre-compiled by time we get here and also
* re-usable on the SysprofDocument for other tooling that may need to access
* that.
*
* The symbolizer will need to gain API to use those too.
*
* Some of this will need to be done asynchronously as well because decoding
* from debuginfod could be quite costly in disk/network/time.
*/
n_addresses = sysprof_document_traceable_get_stack_depth (traceable); n_addresses = sysprof_document_traceable_get_stack_depth (traceable);
addresses = g_alloca (sizeof (guint64) * n_addresses); addresses = g_alloca (sizeof (guint64) * n_addresses);
sysprof_document_traceable_get_stack_addresses (traceable, addresses, n_addresses); sysprof_document_traceable_get_stack_addresses (traceable, addresses, n_addresses);
@ -139,16 +124,10 @@ sysprof_document_symbols_add_traceable (SysprofDocumentSymbols *self,
} }
else else
{ {
g_autoptr(SysprofSymbol) symbol = _sysprof_symbolizer_symbolize (symbolizer, time, pid, address); g_autoptr(SysprofSymbol) symbol = _sysprof_symbolizer_symbolize (symbolizer, mount_namespace, address_layout, pid, address);
if (symbol != NULL) if (symbol != NULL)
sysprof_symbol_cache_take (symbol_cache, g_steal_pointer (&symbol)); sysprof_symbol_cache_take (symbol_cache, g_steal_pointer (&symbol));
/* TODO: This isn't the API we'll use for symbolizing, it just gets
* some plumbing in place. Additionally, we'll probably cache all these
* values here so that we can skip calling the symbolizer at all for
* subsequent symbols within a given range.
*/
} }
} }
} }
@ -207,11 +186,20 @@ sysprof_document_symbols_worker (GTask *task,
do do
{ {
g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i); g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i);
int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable));
SysprofMountNamespace *mount_namespace = g_hash_table_lookup (state->pid_to_mount_namespaces, GINT_TO_POINTER (pid));
SysprofAddressLayout *address_layout = g_hash_table_lookup (state->pid_to_address_layouts, GINT_TO_POINTER (pid));
SysprofSymbolCache *symbol_cache = g_hash_table_lookup (state->symbols->pid_to_symbol_cache, GINT_TO_POINTER (pid));
if (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable)) if (symbol_cache == NULL)
sysprof_document_symbols_add_traceable (state->symbols, {
traceable, symbol_cache = sysprof_symbol_cache_new ();
state->symbolizer); g_hash_table_insert (state->symbols->pid_to_symbol_cache,
GINT_TO_POINTER (pid),
symbol_cache);
}
sysprof_document_symbols_add_traceable (state->symbols, traceable, state->symbolizer, mount_namespace, address_layout, symbol_cache);
} }
while (gtk_bitset_iter_next (&iter, &i)); while (gtk_bitset_iter_next (&iter, &i));
} }
@ -224,6 +212,8 @@ sysprof_document_symbols_worker (GTask *task,
void void
_sysprof_document_symbols_new (SysprofDocument *document, _sysprof_document_symbols_new (SysprofDocument *document,
SysprofSymbolizer *symbolizer, SysprofSymbolizer *symbolizer,
GHashTable *pid_to_mount_namespaces,
GHashTable *pid_to_address_layouts,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
@ -238,6 +228,8 @@ _sysprof_document_symbols_new (SysprofDocument *document,
state->document = g_object_ref (document); state->document = g_object_ref (document);
state->symbolizer = g_object_ref (symbolizer); state->symbolizer = g_object_ref (symbolizer);
state->symbols = g_object_new (SYSPROF_TYPE_DOCUMENT_SYMBOLS, NULL); state->symbols = g_object_new (SYSPROF_TYPE_DOCUMENT_SYMBOLS, NULL);
state->pid_to_address_layouts = g_hash_table_ref (pid_to_address_layouts);
state->pid_to_mount_namespaces = g_hash_table_ref (pid_to_mount_namespaces);
task = g_task_new (NULL, cancellable, callback, user_data); task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, _sysprof_document_symbols_new); g_task_set_source_tag (task, _sysprof_document_symbols_new);

View File

@ -56,8 +56,8 @@ struct _SysprofDocument
GtkBitset *mmaps; GtkBitset *mmaps;
GHashTable *files_first_position; GHashTable *files_first_position;
GHashTable *pid_to_mmaps; GHashTable *pid_to_address_layouts;
GHashTable *pid_to_mountinfo; GHashTable *pid_to_mount_namespaces;
SysprofMountNamespace *mount_namespace; SysprofMountNamespace *mount_namespace;
@ -152,8 +152,8 @@ sysprof_document_finalize (GObject *object)
g_clear_pointer (&self->strings, sysprof_strings_unref); g_clear_pointer (&self->strings, sysprof_strings_unref);
g_clear_pointer (&self->pid_to_mmaps, g_hash_table_unref); g_clear_pointer (&self->pid_to_address_layouts, g_hash_table_unref);
g_clear_pointer (&self->pid_to_mountinfo, g_hash_table_unref); g_clear_pointer (&self->pid_to_mount_namespaces, g_hash_table_unref);
g_clear_pointer (&self->mapped_file, g_mapped_file_unref); g_clear_pointer (&self->mapped_file, g_mapped_file_unref);
g_clear_pointer (&self->frames, g_array_unref); g_clear_pointer (&self->frames, g_array_unref);
@ -189,35 +189,16 @@ sysprof_document_init (SysprofDocument *self)
self->mmaps = gtk_bitset_new_empty (); self->mmaps = gtk_bitset_new_empty ();
self->files_first_position = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); self->files_first_position = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
self->pid_to_mmaps = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_ptr_array_unref); self->pid_to_address_layouts = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
self->pid_to_mountinfo = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref); self->pid_to_mount_namespaces = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
self->mount_namespace = sysprof_mount_namespace_new (); self->mount_namespace = sysprof_mount_namespace_new ();
} }
static int
compare_map (gconstpointer a,
gconstpointer b)
{
SysprofDocumentMmap * const *mmap_a = a;
SysprofDocumentMmap * const *mmap_b = b;
SysprofAddress addr_a = sysprof_document_mmap_get_start_address (*mmap_a);
SysprofAddress addr_b = sysprof_document_mmap_get_start_address (*mmap_b);
if (addr_a < addr_b)
return -1;
else if (addr_a > addr_b)
return 1;
else
return 0;
}
static void static void
sysprof_document_load_memory_maps (SysprofDocument *self) sysprof_document_load_memory_maps (SysprofDocument *self)
{ {
GtkBitsetIter iter; GtkBitsetIter iter;
GHashTableIter hiter;
gpointer key, value;
guint i; guint i;
g_assert (SYSPROF_IS_DOCUMENT (self)); g_assert (SYSPROF_IS_DOCUMENT (self));
@ -228,25 +209,18 @@ sysprof_document_load_memory_maps (SysprofDocument *self)
{ {
g_autoptr(SysprofDocumentMmap) map = sysprof_document_get_item ((GListModel *)self, i); g_autoptr(SysprofDocumentMmap) map = sysprof_document_get_item ((GListModel *)self, i);
int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (map)); int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (map));
GPtrArray *maps = g_hash_table_lookup (self->pid_to_mmaps, GINT_TO_POINTER (pid)); SysprofAddressLayout *address_layout = g_hash_table_lookup (self->pid_to_address_layouts, GINT_TO_POINTER (pid));
if G_UNLIKELY (maps == NULL) if G_UNLIKELY (address_layout == NULL)
{ {
maps = g_ptr_array_new_with_free_func (g_object_unref); address_layout = sysprof_address_layout_new ();
g_hash_table_insert (self->pid_to_mmaps, GINT_TO_POINTER (pid), maps); g_hash_table_insert (self->pid_to_address_layouts, GINT_TO_POINTER (pid), address_layout);
} }
g_ptr_array_add (maps, g_steal_pointer (&map)); sysprof_address_layout_take (address_layout, g_steal_pointer (&map));
} }
while (gtk_bitset_iter_next (&iter, &i)); while (gtk_bitset_iter_next (&iter, &i));
} }
g_hash_table_iter_init (&hiter, self->pid_to_mmaps);
while (g_hash_table_iter_next (&hiter, &key, &value))
{
GPtrArray *ar = value;
g_ptr_array_sort (ar, compare_map);
}
} }
static void static void
@ -358,7 +332,7 @@ sysprof_document_load_mountinfo (SysprofDocument *self,
sysprof_mount_namespace_add_mount (mount_namespace, g_steal_pointer (&mount)); sysprof_mount_namespace_add_mount (mount_namespace, g_steal_pointer (&mount));
} }
g_hash_table_insert (self->pid_to_mountinfo, g_hash_table_insert (self->pid_to_mount_namespaces,
GINT_TO_POINTER (pid), GINT_TO_POINTER (pid),
g_steal_pointer (&mount_namespace)); g_steal_pointer (&mount_namespace));
} }
@ -371,7 +345,7 @@ sysprof_document_load_mountinfos (SysprofDocument *self)
g_assert (SYSPROF_IS_DOCUMENT (self)); g_assert (SYSPROF_IS_DOCUMENT (self));
g_hash_table_iter_init (&hiter, self->pid_to_mmaps); g_hash_table_iter_init (&hiter, self->pid_to_address_layouts);
while (g_hash_table_iter_next (&hiter, &key, &value)) while (g_hash_table_iter_next (&hiter, &key, &value))
{ {
g_autoptr(SysprofMountNamespace) mount_namespace = sysprof_mount_namespace_new (); g_autoptr(SysprofMountNamespace) mount_namespace = sysprof_mount_namespace_new ();
@ -581,16 +555,25 @@ sysprof_document_symbolize_prepare_cb (GObject *object,
SysprofSymbolizer *symbolizer = (SysprofSymbolizer *)object; SysprofSymbolizer *symbolizer = (SysprofSymbolizer *)object;
g_autoptr(GTask) task = user_data; g_autoptr(GTask) task = user_data;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
SysprofDocument *self;
g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer)); g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer));
g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task)); g_assert (G_IS_TASK (task));
self = g_task_get_source_object (task);
g_assert (self != NULL);
g_assert (SYSPROF_IS_DOCUMENT (self));
g_assert (self->pid_to_mount_namespaces != NULL);
if (!_sysprof_symbolizer_prepare_finish (symbolizer, result, &error)) if (!_sysprof_symbolizer_prepare_finish (symbolizer, result, &error))
g_task_return_error (task, g_steal_pointer (&error)); g_task_return_error (task, g_steal_pointer (&error));
else else
_sysprof_document_symbols_new (g_task_get_source_object (task), _sysprof_document_symbols_new (g_task_get_source_object (task),
symbolizer, symbolizer,
self->pid_to_mount_namespaces,
self->pid_to_address_layouts,
g_task_get_cancellable (task), g_task_get_cancellable (task),
sysprof_document_symbolize_symbols_cb, sysprof_document_symbolize_symbols_cb,
g_object_ref (task)); g_object_ref (task));

View File

@ -118,17 +118,18 @@ sysprof_multi_symbolizer_prepare_finish (SysprofSymbolizer *symbolizer,
} }
static SysprofSymbol * static SysprofSymbol *
sysprof_multi_symbolizer_symbolize (SysprofSymbolizer *symbolizer, sysprof_multi_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
gint64 time, SysprofMountNamespace *mount_namespace,
int pid, SysprofAddressLayout *address_layout,
SysprofAddress address) int pid,
SysprofAddress address)
{ {
SysprofMultiSymbolizer *self = SYSPROF_MULTI_SYMBOLIZER (symbolizer); SysprofMultiSymbolizer *self = SYSPROF_MULTI_SYMBOLIZER (symbolizer);
for (guint i = 0; i < self->symbolizers->len; i++) for (guint i = 0; i < self->symbolizers->len; i++)
{ {
SysprofSymbolizer *child = g_ptr_array_index (self->symbolizers, i); SysprofSymbolizer *child = g_ptr_array_index (self->symbolizers, i);
SysprofSymbol *symbol = _sysprof_symbolizer_symbolize (child, time, pid, address); SysprofSymbol *symbol = _sysprof_symbolizer_symbolize (child, mount_namespace, address_layout, pid, address);
if (symbol != NULL) if (symbol != NULL)
return symbol; return symbol;

View File

@ -20,9 +20,11 @@
#pragma once #pragma once
#include "sysprof-address-layout-private.h"
#include "sysprof-document.h" #include "sysprof-document.h"
#include "sysprof-symbol.h" #include "sysprof-symbol.h"
#include "sysprof-symbolizer.h" #include "sysprof-symbolizer.h"
#include "sysprof-mount-namespace-private.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -37,32 +39,34 @@ struct _SysprofSymbolizerClass
{ {
GObjectClass parent_class; GObjectClass parent_class;
void (*prepare_async) (SysprofSymbolizer *self, void (*prepare_async) (SysprofSymbolizer *self,
SysprofDocument *document, SysprofDocument *document,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
gboolean (*prepare_finish) (SysprofSymbolizer *self, gboolean (*prepare_finish) (SysprofSymbolizer *self,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
SysprofSymbol *(*symbolize) (SysprofSymbolizer *self, SysprofSymbol *(*symbolize) (SysprofSymbolizer *self,
gint64 time, SysprofMountNamespace *mount_namespace,
int pid, SysprofAddressLayout *address_layout,
SysprofAddress address); int pid,
SysprofAddress address);
}; };
void _sysprof_symbolizer_prepare_async (SysprofSymbolizer *self, void _sysprof_symbolizer_prepare_async (SysprofSymbolizer *self,
SysprofDocument *document, SysprofDocument *document,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
gboolean _sysprof_symbolizer_prepare_finish (SysprofSymbolizer *self, gboolean _sysprof_symbolizer_prepare_finish (SysprofSymbolizer *self,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
SysprofSymbol *_sysprof_symbolizer_symbolize (SysprofSymbolizer *self, SysprofSymbol *_sysprof_symbolizer_symbolize (SysprofSymbolizer *self,
gint64 time, SysprofMountNamespace *mount_namespace,
int pid, SysprofAddressLayout *address_layout,
SysprofAddress address); int pid,
SysprofAddress address);
G_END_DECLS G_END_DECLS

View File

@ -91,10 +91,11 @@ _sysprof_symbolizer_prepare_finish (SysprofSymbolizer *self,
} }
SysprofSymbol * SysprofSymbol *
_sysprof_symbolizer_symbolize (SysprofSymbolizer *self, _sysprof_symbolizer_symbolize (SysprofSymbolizer *self,
gint64 time, SysprofMountNamespace *mount_namespace,
int pid, SysprofAddressLayout *address_layout,
SysprofAddress address) int pid,
SysprofAddress address)
{ {
return SYSPROF_SYMBOLIZER_GET_CLASS (self)->symbolize (self, time, pid, address); return SYSPROF_SYMBOLIZER_GET_CLASS (self)->symbolize (self, mount_namespace, address_layout, pid, address);
} }