diff --git a/src/libsysprof-analyze/meson.build b/src/libsysprof-analyze/meson.build index bd779c7f..ba11a216 100644 --- a/src/libsysprof-analyze/meson.build +++ b/src/libsysprof-analyze/meson.build @@ -14,7 +14,6 @@ libsysprof_analyze_public_sources = [ 'sysprof-document-mmap.c', 'sysprof-document-process.c', 'sysprof-document-sample.c', - 'sysprof-document-symbols.c', 'sysprof-document-traceable.c', 'sysprof-kallsyms-symbolizer.c', 'sysprof-multi-symbolizer.c', @@ -26,6 +25,7 @@ libsysprof_analyze_public_sources = [ libsysprof_analyze_private_sources = [ 'sysprof-address-layout.c', 'sysprof-document-bitset-index.c', + 'sysprof-document-symbols.c', 'sysprof-mount.c', 'sysprof-mount-device.c', 'sysprof-mount-namespace.c', @@ -51,7 +51,6 @@ libsysprof_analyze_public_headers = [ 'sysprof-document-mmap.h', 'sysprof-document-process.h', 'sysprof-document-sample.h', - 'sysprof-document-symbols.h', 'sysprof-document-traceable.h', 'sysprof-mount.h', 'sysprof-kallsyms-symbolizer.h', diff --git a/src/libsysprof-analyze/sysprof-analyze.h b/src/libsysprof-analyze/sysprof-analyze.h index f751127a..0461cd82 100644 --- a/src/libsysprof-analyze/sysprof-analyze.h +++ b/src/libsysprof-analyze/sysprof-analyze.h @@ -40,7 +40,6 @@ G_BEGIN_DECLS # include "sysprof-document-mmap.h" # include "sysprof-document-process.h" # include "sysprof-document-sample.h" -# include "sysprof-document-symbols.h" # include "sysprof-document-traceable.h" # include "sysprof-mount.h" # include "sysprof-kallsyms-symbolizer.h" diff --git a/src/libsysprof-analyze/sysprof-document-loader.c b/src/libsysprof-analyze/sysprof-document-loader.c index 7d4fc8fe..cfe65c52 100644 --- a/src/libsysprof-analyze/sysprof-document-loader.c +++ b/src/libsysprof-analyze/sysprof-document-loader.c @@ -20,8 +20,13 @@ #include "config.h" +#include +#include + +#include "sysprof-bundled-symbolizer.h" #include "sysprof-document-loader.h" #include "sysprof-document-private.h" +#include "sysprof-multi-symbolizer.h" struct _SysprofDocumentLoader { @@ -45,6 +50,105 @@ G_DEFINE_FINAL_TYPE (SysprofDocumentLoader, sysprof_document_loader, G_TYPE_OBJE static GParamSpec *properties [N_PROPS]; +static void +mapped_file_by_filename (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GMappedFile) mapped_file = g_mapped_file_new (task_data, FALSE, &error); + + if (mapped_file != NULL) + g_task_return_pointer (task, + g_steal_pointer (&mapped_file), + (GDestroyNotify)g_mapped_file_unref); + else + g_task_return_error (task, g_steal_pointer (&error)); +} + +static void +mapped_file_new_async (const char *filename, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = g_task_new (NULL, cancellable, callback, user_data); + g_task_set_task_data (task, g_strdup (filename), g_free); + g_task_run_in_thread (task, mapped_file_by_filename); +} + +static void +mapped_file_by_fd (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GMappedFile) mapped_file = g_mapped_file_new_from_fd (GPOINTER_TO_INT (task_data), FALSE, &error); + + if (mapped_file != NULL) + g_task_return_pointer (task, + g_steal_pointer (&mapped_file), + (GDestroyNotify)g_mapped_file_unref); + else + g_task_return_error (task, g_steal_pointer (&error)); +} + +static void +close_fd (gpointer data) +{ + int fd = GPOINTER_TO_INT (data); + close (fd); +} + +static void +mapped_file_new_from_fd_async (int fd, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + int copy_fd; + + task = g_task_new (NULL, cancellable, callback, user_data); + + if (-1 == (copy_fd = dup (fd))) + { + int errsv = errno; + g_task_return_new_error (task, + G_IO_ERROR, + g_io_error_from_errno (errsv), + "%s", + g_strerror (errsv)); + return; + } + + g_task_set_task_data (task, GINT_TO_POINTER (copy_fd), close_fd); + g_task_run_in_thread (task, mapped_file_by_fd); +} + +static GMappedFile * +mapped_file_new_finish (GAsyncResult *result, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +set_default_symbolizer (SysprofDocumentLoader *self) +{ + g_autoptr(SysprofMultiSymbolizer) multi = NULL; + + g_assert (SYSPROF_IS_DOCUMENT_LOADER (self)); + + g_clear_object (&self->symbolizer); + + multi = sysprof_multi_symbolizer_new (); + sysprof_multi_symbolizer_take (multi, sysprof_bundled_symbolizer_new ()); + self->symbolizer = SYSPROF_SYMBOLIZER (g_steal_pointer (&multi)); +} + static void sysprof_document_loader_finalize (GObject *object) { @@ -140,6 +244,8 @@ static void sysprof_document_loader_init (SysprofDocumentLoader *self) { self->fd = -1; + + set_default_symbolizer (self); } SysprofDocumentLoader * @@ -210,7 +316,11 @@ sysprof_document_loader_set_symbolizer (SysprofDocumentLoader *self, g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self)); if (g_set_object (&self->symbolizer, symbolizer)) - g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYMBOLIZER]); + { + if (self->symbolizer == NULL) + set_default_symbolizer (self); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYMBOLIZER]); + } } /** @@ -249,12 +359,11 @@ sysprof_document_loader_get_message (SysprofDocumentLoader *self) } static void -sysprof_document_loader_load_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) +sysprof_document_loader_load_symbols_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) { SysprofDocument *document = (SysprofDocument *)object; - g_autoptr(SysprofDocumentSymbols) symbols = NULL; g_autoptr(GError) error = NULL; g_autoptr(GTask) task = user_data; @@ -262,12 +371,61 @@ sysprof_document_loader_load_cb (GObject *object, g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_TASK (task)); - if (!(symbols = _sysprof_document_symbolize_finish (document, result, &error))) + if (!_sysprof_document_symbolize_finish (document, result, &error)) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_pointer (task, g_object_ref (document), g_object_unref); } +static void +sysprof_document_loader_load_document_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(SysprofDocument) document = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + SysprofSymbolizer *symbolizer; + + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + symbolizer = g_task_get_task_data (task); + + g_assert (symbolizer != NULL); + g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer)); + + if (!(document = _sysprof_document_new_finish (result, &error))) + g_task_return_error (task, g_steal_pointer (&error)); + else + _sysprof_document_symbolize_async (document, + symbolizer, + g_task_get_cancellable (task), + sysprof_document_loader_load_symbols_cb, + g_object_ref (task)); +} + +static void +sysprof_document_loader_load_mapped_file_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GMappedFile) mapped_file = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + if (!(mapped_file = mapped_file_new_finish (result, &error))) + g_task_return_error (task, g_steal_pointer (&error)); + else + _sysprof_document_new_async (mapped_file, + g_task_get_cancellable (task), + sysprof_document_loader_load_document_cb, + g_object_ref (task)); +} + /** * sysprof_document_loader_load_async: * @self: a #SysprofDocumentLoader @@ -285,43 +443,29 @@ sysprof_document_loader_load_async (SysprofDocumentLoader *self, GAsyncReadyCallback callback, gpointer user_data) { - g_autoptr(SysprofDocument) document = NULL; + g_autoptr(SysprofSymbolizer) symbolizer = NULL; + g_autoptr(GMappedFile) mapped_file = NULL; g_autoptr(GError) error = NULL; g_autoptr(GTask) task = NULL; g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self)); g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (self->filename != NULL || self->fd != -1); task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, g_object_ref (self->symbolizer), g_object_unref); g_task_set_source_tag (task, sysprof_document_loader_load_async); - if (self->fd == -1 && self->filename == NULL) - { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "SysprofDocumentLoader disposition must have fd or filename set"); - return; - } - if (self->fd != -1) - document = _sysprof_document_new_from_fd (self->fd, &error); - else if (self->filename != NULL) - document = _sysprof_document_new (self->filename, &error); + mapped_file_new_from_fd_async (self->fd, + cancellable, + sysprof_document_loader_load_mapped_file_cb, + g_steal_pointer (&task)); else - g_assert_not_reached (); - - /* TODO: This will probably get renamed to load_async as we want - * to always have a symbolizer for loading. Additionally, the - * document will deal with caches directly instead of the symbols - * object. - */ - - _sysprof_document_symbolize_async (document, - self->symbolizer, - cancellable, - sysprof_document_loader_load_cb, - g_steal_pointer (&task)); + mapped_file_new_async (self->filename, + cancellable, + sysprof_document_loader_load_mapped_file_cb, + g_steal_pointer (&task)); } /** diff --git a/src/libsysprof-analyze/sysprof-document-private.h b/src/libsysprof-analyze/sysprof-document-private.h index 5993e6ea..a289a073 100644 --- a/src/libsysprof-analyze/sysprof-document-private.h +++ b/src/libsysprof-analyze/sysprof-document-private.h @@ -23,24 +23,27 @@ #include #include "sysprof-document.h" +#include "sysprof-symbolizer.h" G_BEGIN_DECLS -SysprofDocument *_sysprof_document_new (const char *filename, - GError **error); -SysprofDocument *_sysprof_document_new_from_fd (int capture_fd, - GError **error); -void _sysprof_document_symbolize_async (SysprofDocument *self, - SysprofSymbolizer *symbolizer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -SysprofDocumentSymbols *_sysprof_document_symbolize_finish (SysprofDocument *self, - GAsyncResult *result, - GError **error); -gboolean _sysprof_document_is_native (SysprofDocument *self); -char *_sysprof_document_ref_string (SysprofDocument *self, - const char *name); -GtkBitset *_sysprof_document_traceables (SysprofDocument *self); +void _sysprof_document_new_async (GMappedFile *mapped_file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SysprofDocument *_sysprof_document_new_finish (GAsyncResult *result, + GError **error); +void _sysprof_document_symbolize_async (SysprofDocument *self, + SysprofSymbolizer *symbolizer, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean _sysprof_document_symbolize_finish (SysprofDocument *self, + GAsyncResult *result, + GError **error); +gboolean _sysprof_document_is_native (SysprofDocument *self); +char *_sysprof_document_ref_string (SysprofDocument *self, + const char *name); +GtkBitset *_sysprof_document_traceables (SysprofDocument *self); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-document-symbols-private.h b/src/libsysprof-analyze/sysprof-document-symbols-private.h index 58ac1faa..680b6468 100644 --- a/src/libsysprof-analyze/sysprof-document-symbols-private.h +++ b/src/libsysprof-analyze/sysprof-document-symbols-private.h @@ -21,19 +21,28 @@ #pragma once #include "sysprof-document.h" -#include "sysprof-document-symbols.h" #include "sysprof-process-info-private.h" +#include "sysprof-symbolizer.h" +#include "sysprof-symbol.h" G_BEGIN_DECLS -void _sysprof_document_symbols_new (SysprofDocument *document, - SysprofStrings *strings, - SysprofSymbolizer *symbolizer, - GHashTable *pid_to_process_info, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -SysprofDocumentSymbols *_sysprof_document_symbols_new_finish (GAsyncResult *result, - GError **error); +#define SYSPROF_TYPE_DOCUMENT_SYMBOLS (sysprof_document_symbols_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofDocumentSymbols, sysprof_document_symbols, SYSPROF, DOCUMENT_SYMBOLS, GObject) + +void _sysprof_document_symbols_new (SysprofDocument *document, + SysprofStrings *strings, + SysprofSymbolizer *symbolizer, + GHashTable *pid_to_process_info, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SysprofDocumentSymbols *_sysprof_document_symbols_new_finish (GAsyncResult *result, + GError **error); +SysprofSymbol *_sysprof_document_symbols_lookup (SysprofDocumentSymbols *symbols, + int pid, + SysprofAddressContext context, + SysprofAddress address); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-document-symbols.c b/src/libsysprof-analyze/sysprof-document-symbols.c index b087d0ab..9c499611 100644 --- a/src/libsysprof-analyze/sysprof-document-symbols.c +++ b/src/libsysprof-analyze/sysprof-document-symbols.c @@ -25,6 +25,7 @@ #include "sysprof-document-symbols-private.h" #include "sysprof-document-traceable.h" #include "sysprof-mount-namespace-private.h" +#include "sysprof-no-symbolizer.h" #include "sysprof-symbol-private.h" #include "sysprof-symbol-cache-private.h" #include "sysprof-symbolizer-private.h" @@ -175,7 +176,8 @@ sysprof_document_symbols_worker (GTask *task, } /* Walk through the available traceables which need symbols extracted */ - if (gtk_bitset_iter_init_first (&iter, bitset, &i)) + if (!SYSPROF_IS_NO_SYMBOLIZER (state->symbolizer) && + gtk_bitset_iter_init_first (&iter, bitset, &i)) { do { @@ -243,7 +245,7 @@ _sysprof_document_symbols_new_finish (GAsyncResult *result, } /** - * sysprof_document_symbols_lookup: + * _sysprof_document_symbols_lookup: * @self: a #SysprofDocumentSymbols * @pid: the process identifier * @context: the #SysprofAddressContext for the address @@ -254,10 +256,10 @@ _sysprof_document_symbols_new_finish (GAsyncResult *result, * Returns: (transfer none) (nullable): a #SysprofSymbol or %NULL */ SysprofSymbol * -sysprof_document_symbols_lookup (SysprofDocumentSymbols *self, - int pid, - SysprofAddressContext context, - SysprofAddress address) +_sysprof_document_symbols_lookup (SysprofDocumentSymbols *self, + int pid, + SysprofAddressContext context, + SysprofAddress address) { SysprofAddressContext new_context; SysprofProcessInfo *process_info; diff --git a/src/libsysprof-analyze/sysprof-document-symbols.h b/src/libsysprof-analyze/sysprof-document-symbols.h deleted file mode 100644 index 556476f5..00000000 --- a/src/libsysprof-analyze/sysprof-document-symbols.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * sysprof-document-symbols.h - * - * Copyright 2023 Christian Hergert - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include - -#include - -#include "sysprof-symbol.h" - -G_BEGIN_DECLS - -#define SYSPROF_TYPE_DOCUMENT_SYMBOLS (sysprof_document_symbols_get_type()) - -SYSPROF_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (SysprofDocumentSymbols, sysprof_document_symbols, SYSPROF, DOCUMENT_SYMBOLS, GObject) - -SYSPROF_AVAILABLE_IN_ALL -SysprofSymbol *sysprof_document_symbols_lookup (SysprofDocumentSymbols *symbols, - int pid, - SysprofAddressContext context, - SysprofAddress address); - -G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-document.c b/src/libsysprof-analyze/sysprof-document.c index 0449944a..2e8911e8 100644 --- a/src/libsysprof-analyze/sysprof-document.c +++ b/src/libsysprof-analyze/sysprof-document.c @@ -63,6 +63,8 @@ struct _SysprofDocument SysprofMountNamespace *mount_namespace; + SysprofDocumentSymbols *symbols; + SysprofCaptureFileHeader header; guint needs_swap : 1; }; @@ -197,6 +199,7 @@ sysprof_document_finalize (GObject *object) g_clear_pointer (&self->pids, gtk_bitset_unref); g_clear_object (&self->mount_namespace); + g_clear_object (&self->symbols); g_clear_pointer (&self->files_first_position, g_hash_table_unref); @@ -390,26 +393,34 @@ sysprof_document_load_mountinfos (SysprofDocument *self) } } -static gboolean -sysprof_document_load (SysprofDocument *self, - int capture_fd, - GError **error) +static void +sysprof_document_load_worker (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { + g_autoptr(SysprofDocument) self = NULL; g_autoptr(GHashTable) files = NULL; + GMappedFile *mapped_file = task_data; goffset pos; gsize len; - g_assert (SYSPROF_IS_DOCUMENT (self)); - g_assert (capture_fd > -1); + g_assert (source_object == NULL); + g_assert (mapped_file != NULL); - if (!(self->mapped_file = g_mapped_file_new_from_fd (capture_fd, FALSE, error))) - return FALSE; - - self->base = (const guint8 *)g_mapped_file_get_contents (self->mapped_file); - len = g_mapped_file_get_length (self->mapped_file); + self = g_object_new (SYSPROF_TYPE_DOCUMENT, NULL); + self->mapped_file = g_mapped_file_ref (mapped_file); + self->base = (const guint8 *)g_mapped_file_get_contents (mapped_file); + len = g_mapped_file_get_length (mapped_file); if (len < sizeof self->header) - return FALSE; + { + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "File header too short"); + return; + } /* Keep a copy of our header */ memcpy (&self->header, self->base, sizeof self->header); @@ -479,77 +490,39 @@ sysprof_document_load (SysprofDocument *self, sysprof_document_load_mountinfos (self); sysprof_document_load_memory_maps (self); - return TRUE; + g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref); } -/** - * _sysprof_document_new_from_fd: - * @capture_fd: a file-descriptor to be mapped - * @error: a location for a #GError, or %NULL - * - * Creates a new memory map using @capture_fd to read the underlying - * Sysprof capture. - * - * No ownership of @capture_fd is transferred, and the caller may close - * @capture_fd after calling this function. - * - * Returns: A #SysprofDocument if successful; otherwise %NULL - * and @error is set. - */ -SysprofDocument * -_sysprof_document_new_from_fd (int capture_fd, - GError **error) +void +_sysprof_document_new_async (GMappedFile *mapped_file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_autoptr(SysprofDocument) self = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (capture_fd > -1, NULL); + g_return_if_fail (mapped_file != NULL); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); - self = g_object_new (SYSPROF_TYPE_DOCUMENT, NULL); - - if (!sysprof_document_load (self, capture_fd, error)) - return NULL; - - return g_steal_pointer (&self); + task = g_task_new (NULL, cancellable, callback, user_data); + g_task_set_source_tag (task, _sysprof_document_new_async); + g_task_set_task_data (task, + g_mapped_file_ref (mapped_file), + (GDestroyNotify)g_mapped_file_unref); + g_task_run_in_thread (task, sysprof_document_load_worker); } -/** - * sysprof_document_new: - * @filename: a path to a capture file - * @error: location for a #GError, or %NULL - * - * Similar to sysprof_document_new_from_fd() but opens the file found - * at @filename as a #GMappedFile. - * - * Returns: a #SysprofDocument if successful; otherwise %NULL - * and @error is set. - * - * Since: 45.0 - */ SysprofDocument * -_sysprof_document_new (const char *filename, - GError **error) +_sysprof_document_new_finish (GAsyncResult *result, + GError **error) { - g_autoptr(SysprofDocument) self = NULL; - g_autofd int capture_fd = -1; + SysprofDocument *ret; - g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (G_IS_TASK (result), NULL); + ret = g_task_propagate_pointer (G_TASK (result), error); + g_return_val_if_fail (!ret || SYSPROF_IS_DOCUMENT (ret), NULL); - if (-1 == (capture_fd = g_open (filename, O_RDONLY|O_CLOEXEC, 0))) - { - int errsv = errno; - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "%s", g_strerror (errsv)); - return NULL; - } - - self = g_object_new (SYSPROF_TYPE_DOCUMENT, NULL); - - if (!sysprof_document_load (self, capture_fd, error)) - return NULL; - - return g_steal_pointer (&self); + return ret; } char * @@ -569,14 +542,25 @@ sysprof_document_symbolize_symbols_cb (GObject *object, g_autoptr(SysprofDocumentSymbols) symbols = NULL; g_autoptr(GTask) task = user_data; g_autoptr(GError) error = NULL; + SysprofDocument *self; g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_TASK (task)); - if ((symbols = _sysprof_document_symbols_new_finish (result, &error))) - g_task_return_pointer (task, g_steal_pointer (&symbols), g_object_unref); - else - g_task_return_error (task, g_steal_pointer (&error)); + if (!(symbols = _sysprof_document_symbols_new_finish (result, &error))) + { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + self = g_task_get_source_object (task); + + g_assert (self != NULL); + g_assert (SYSPROF_IS_DOCUMENT (self)); + + g_set_object (&self->symbols, symbols); + + g_task_return_boolean (task, TRUE); } static void @@ -635,17 +619,17 @@ _sysprof_document_symbolize_async (SysprofDocument *self, g_steal_pointer (&task)); } -SysprofDocumentSymbols * +gboolean _sysprof_document_symbolize_finish (SysprofDocument *self, GAsyncResult *result, GError **error) { - g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), NULL); - g_return_val_if_fail (G_IS_TASK (result), NULL); - g_return_val_if_fail (g_task_is_valid (result, self), NULL); - g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _sysprof_document_symbolize_async, NULL); + g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _sysprof_document_symbolize_async, FALSE); - return g_task_propagate_pointer (G_TASK (result), error); + return g_task_propagate_boolean (G_TASK (result), error); } gboolean @@ -796,3 +780,51 @@ sysprof_document_list_processes (SysprofDocument *self) return _sysprof_document_bitset_index_new (G_LIST_MODEL (self), self->processes); } + +/** + * sysprof_document_symbolize_traceable: (skip) + * @self: a #SysprofDocument + * @traceable: the traceable to extract symbols for + * @symbols: an array to store #SysprofSymbols + * @n_symbols: the number of elements in @symbols + * + * Batch symbolizing of a traceable. + * + * No ownership is transfered into @symbols and may be cheaply + * discarded if using the stack for storage. + * + * Returns: The number of symbols or NULL set in @symbols. + */ +guint +sysprof_document_symbolize_traceable (SysprofDocument *self, + SysprofDocumentTraceable *traceable, + SysprofSymbol **symbols, + guint n_symbols) +{ + SysprofAddressContext last_context = SYSPROF_ADDRESS_CONTEXT_NONE; + SysprofAddress *addresses; + guint n_addresses; + int pid; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), 0); + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable), 0); + + if (n_symbols == 0 || symbols == NULL) + return 0; + + pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); + addresses = g_alloca (sizeof (SysprofAddress) * n_symbols); + n_addresses = sysprof_document_traceable_get_stack_addresses (traceable, addresses, n_symbols); + + for (guint i = 0; i < n_addresses; i++) + { + SysprofAddressContext context; + + symbols[i] = _sysprof_document_symbols_lookup (self->symbols, pid, last_context, addresses[i]); + + if (sysprof_address_is_context_switch (addresses[i], &context)) + last_context = context; + } + + return n_addresses; +} diff --git a/src/libsysprof-analyze/sysprof-document.h b/src/libsysprof-analyze/sysprof-document.h index aed68f10..19567d2d 100644 --- a/src/libsysprof-analyze/sysprof-document.h +++ b/src/libsysprof-analyze/sysprof-document.h @@ -25,8 +25,8 @@ #include #include "sysprof-document-file.h" -#include "sysprof-document-symbols.h" -#include "sysprof-symbolizer.h" +#include "sysprof-document-traceable.h" +#include "sysprof-symbol.h" G_BEGIN_DECLS @@ -36,13 +36,18 @@ SYSPROF_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (SysprofDocument, sysprof_document, SYSPROF, DOCUMENT, GObject) SYSPROF_AVAILABLE_IN_ALL -SysprofDocumentFile *sysprof_document_lookup_file (SysprofDocument *self, - const char *path); +SysprofDocumentFile *sysprof_document_lookup_file (SysprofDocument *self, + const char *path); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_document_list_files (SysprofDocument *self); +GListModel *sysprof_document_list_files (SysprofDocument *self); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_document_list_traceables (SysprofDocument *self); +GListModel *sysprof_document_list_traceables (SysprofDocument *self); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_document_list_processes (SysprofDocument *self); +GListModel *sysprof_document_list_processes (SysprofDocument *self); +SYSPROF_AVAILABLE_IN_ALL +guint sysprof_document_symbolize_traceable (SysprofDocument *self, + SysprofDocumentTraceable *traceable, + SysprofSymbol **symbols, + guint n_symbols); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-multi-symbolizer.c b/src/libsysprof-analyze/sysprof-multi-symbolizer.c index d39008ea..995a3d35 100644 --- a/src/libsysprof-analyze/sysprof-multi-symbolizer.c +++ b/src/libsysprof-analyze/sysprof-multi-symbolizer.c @@ -181,8 +181,8 @@ sysprof_multi_symbolizer_new (void) * that will be queried when @self is queried for symbols. */ void -sysprof_multi_symbolizer_add (SysprofMultiSymbolizer *self, - SysprofSymbolizer *symbolizer) +sysprof_multi_symbolizer_take (SysprofMultiSymbolizer *self, + SysprofSymbolizer *symbolizer) { g_return_if_fail (SYSPROF_IS_MULTI_SYMBOLIZER (self)); g_return_if_fail (SYSPROF_IS_SYMBOLIZER (symbolizer)); diff --git a/src/libsysprof-analyze/sysprof-multi-symbolizer.h b/src/libsysprof-analyze/sysprof-multi-symbolizer.h index 9beffe91..2ac53f47 100644 --- a/src/libsysprof-analyze/sysprof-multi-symbolizer.h +++ b/src/libsysprof-analyze/sysprof-multi-symbolizer.h @@ -37,7 +37,7 @@ GType sysprof_multi_symbolizer_get_type (void) G_GNUC_CONST; SYSPROF_AVAILABLE_IN_ALL SysprofMultiSymbolizer *sysprof_multi_symbolizer_new (void); SYSPROF_AVAILABLE_IN_ALL -void sysprof_multi_symbolizer_add (SysprofMultiSymbolizer *self, +void sysprof_multi_symbolizer_take (SysprofMultiSymbolizer *self, SysprofSymbolizer *symbolizer); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofMultiSymbolizer, g_object_unref) diff --git a/src/libsysprof-analyze/sysprof-no-symbolizer.c b/src/libsysprof-analyze/sysprof-no-symbolizer.c index 9f803c5c..372fcfe7 100644 --- a/src/libsysprof-analyze/sysprof-no-symbolizer.c +++ b/src/libsysprof-analyze/sysprof-no-symbolizer.c @@ -21,12 +21,18 @@ #include "config.h" #include "sysprof-no-symbolizer.h" +#include "sysprof-symbolizer-private.h" struct _SysprofNoSymbolizer { SysprofSymbolizer parent_instance; }; +struct _SysprofNoSymbolizerClass +{ + SysprofSymbolizerClass parent_class; +}; + G_DEFINE_FINAL_TYPE (SysprofNoSymbolizer, sysprof_no_symbolizer, SYSPROF_TYPE_SYMBOLIZER) static SysprofSymbol * @@ -51,8 +57,20 @@ sysprof_no_symbolizer_init (SysprofNoSymbolizer *self) { } +/** + * sysprof_no_symbolizer_get: + * + * Gets a #SysprofSymbolizer that will never symbolize. + * + * Returns: (transfer none): a #SysprofSymbolizer + */ SysprofSymbolizer * -sysprof_no_symbolizer_new (void) +sysprof_no_symbolizer_get (void) { - return g_object_new (SYSPROF_TYPE_NO_SYMBOLIZER, NULL); + static SysprofSymbolizer *instance; + + if (g_once_init_enter (&instance)) + g_once_init_leave (&instance, g_object_new (SYSPROF_TYPE_NO_SYMBOLIZER, NULL)); + + return instance; } diff --git a/src/libsysprof-analyze/sysprof-no-symbolizer.h b/src/libsysprof-analyze/sysprof-no-symbolizer.h index ebe620b1..e958b670 100644 --- a/src/libsysprof-analyze/sysprof-no-symbolizer.h +++ b/src/libsysprof-analyze/sysprof-no-symbolizer.h @@ -20,18 +20,23 @@ #pragma once -#include - #include "sysprof-symbolizer.h" G_BEGIN_DECLS -#define SYSPROF_TYPE_NO_SYMBOLIZER (sysprof_no_symbolizer_get_type()) +#define SYSPROF_TYPE_NO_SYMBOLIZER (sysprof_no_symbolizer_get_type()) +#define SYSPROF_IS_NO_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_NO_SYMBOLIZER) +#define SYSPROF_NO_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_NO_SYMBOLIZER, SysprofNoSymbolizer) +#define SYSPROF_NO_SYMBOLIZER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_NO_SYMBOLIZER, SysprofNoSymbolizerClass) + +typedef struct _SysprofNoSymbolizer SysprofNoSymbolizer; +typedef struct _SysprofNoSymbolizerClass SysprofNoSymbolizerClass; SYSPROF_AVAILABLE_IN_ALL -G_DECLARE_DERIVABLE_TYPE (SysprofNoSymbolizer, sysprof_no_symbolizer, SYSPROF, NO_SYMBOLIZER, SysprofSymbolizer) - +GType sysprof_no_symbolizer_get_type (void) G_GNUC_CONST; SYSPROF_AVAILABLE_IN_ALL -SysprofSymbolizer *sysprof_no_symbolizer_new (void); +SysprofSymbolizer *sysprof_no_symbolizer_get (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofNoSymbolizer, g_object_unref) G_END_DECLS diff --git a/src/libsysprof-analyze/tests/test-capture-model.c b/src/libsysprof-analyze/tests/test-capture-model.c index 2e16ee44..ee4252b4 100644 --- a/src/libsysprof-analyze/tests/test-capture-model.c +++ b/src/libsysprof-analyze/tests/test-capture-model.c @@ -9,9 +9,10 @@ int main (int argc, char *argv[]) { - SysprofDocument *document; + g_autoptr(SysprofDocumentLoader) loader = NULL; + g_autoptr(SysprofDocument) document = NULL; + g_autoptr(GError) error = NULL; const char *filename; - GError *error = NULL; guint n_items; sysprof_clock_init (); @@ -24,7 +25,10 @@ main (int argc, filename = argv[1]; - if (!(document = _sysprof_document_new (filename, &error))) + loader = sysprof_document_loader_new (filename); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to load %s: %s\n", filename, error->message); @@ -88,7 +92,5 @@ main (int argc, g_printerr ("%u frames\n", n_items); - g_clear_object (&document); - return 0; } diff --git a/src/libsysprof-analyze/tests/test-list-files.c b/src/libsysprof-analyze/tests/test-list-files.c index a79c4a2d..78b3ae06 100644 --- a/src/libsysprof-analyze/tests/test-list-files.c +++ b/src/libsysprof-analyze/tests/test-list-files.c @@ -26,6 +26,7 @@ int main (int argc, char *argv[]) { + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) files = NULL; g_autoptr(GError) error = NULL; @@ -37,7 +38,10 @@ main (int argc, return 1; } - if (!(document = _sysprof_document_new (argv[1], &error))) + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to open capture: %s\n", error->message); return 1; diff --git a/src/libsysprof-analyze/tests/test-list-processes.c b/src/libsysprof-analyze/tests/test-list-processes.c index d3d419da..5b4fffcf 100644 --- a/src/libsysprof-analyze/tests/test-list-processes.c +++ b/src/libsysprof-analyze/tests/test-list-processes.c @@ -26,6 +26,7 @@ int main (int argc, char *argv[]) { + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) processes = NULL; g_autoptr(GError) error = NULL; @@ -37,7 +38,10 @@ main (int argc, return 1; } - if (!(document = _sysprof_document_new (argv[1], &error))) + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to open capture: %s\n", error->message); return 1; diff --git a/src/libsysprof-analyze/tests/test-print-file.c b/src/libsysprof-analyze/tests/test-print-file.c index cd8d3720..1e49f19d 100644 --- a/src/libsysprof-analyze/tests/test-print-file.c +++ b/src/libsysprof-analyze/tests/test-print-file.c @@ -26,6 +26,7 @@ int main (int argc, char *argv[]) { + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocumentFile) file = NULL; g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) files = NULL; @@ -38,7 +39,10 @@ main (int argc, return 1; } - if (!(document = _sysprof_document_new (argv[1], &error))) + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to open capture: %s\n", error->message); return 1; diff --git a/src/libsysprof-analyze/tests/test-symbolize.c b/src/libsysprof-analyze/tests/test-symbolize.c index 8265d2da..29e5e3ef 100644 --- a/src/libsysprof-analyze/tests/test-symbolize.c +++ b/src/libsysprof-analyze/tests/test-symbolize.c @@ -7,63 +7,88 @@ static GMainLoop *main_loop; static void -symbolize_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) +load_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) { - SysprofDocument *document = (SysprofDocument *)object; - g_autoptr(SysprofDocumentSymbols) symbols = NULL; + SysprofDocumentLoader *loader = (SysprofDocumentLoader *)object; + g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) traceables = NULL; g_autoptr(GError) error = NULL; - SysprofAddress addresses[128]; + g_autoptr(GString) str = NULL; + SysprofSymbol *symbols[128]; + guint n_symbols; guint n_items; - g_assert (SYSPROF_IS_DOCUMENT (document)); + g_assert (SYSPROF_IS_DOCUMENT_LOADER (loader)); g_assert (G_IS_ASYNC_RESULT (result)); - if (!(symbols = _sysprof_document_symbolize_finish (document, result, &error))) - g_error ("Failed to symbolize: %s", error->message); + if (!(document = sysprof_document_loader_load_finish (loader, result, &error))) + g_error ("Failed to load document: %s", error->message); traceables = sysprof_document_list_traceables (document); n_items = g_list_model_get_n_items (traceables); + str = g_string_new (""); + for (guint i = 0; i < n_items; i++) { g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (traceables, i); - SysprofAddressContext last_context; - guint depth; - int pid; + + str->len = 0; + str->str[0] = 0; g_assert (traceable != NULL); g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable)); - last_context = SYSPROF_ADDRESS_CONTEXT_NONE; - pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); - depth = sysprof_document_traceable_get_stack_addresses (traceable, addresses, G_N_ELEMENTS (addresses)); + n_symbols = sysprof_document_symbolize_traceable (document, + traceable, + symbols, + G_N_ELEMENTS (symbols)); g_print ("%s depth=%u pid=%u\n", - G_OBJECT_TYPE_NAME (traceable), depth, pid); + G_OBJECT_TYPE_NAME (traceable), + n_symbols, + sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable))); - for (guint j = 0; j < depth; j++) + for (guint j = 0; j < n_symbols; j++) { - SysprofAddress address = addresses[j]; - SysprofSymbol *symbol = sysprof_document_symbols_lookup (symbols, pid, last_context, address); - SysprofAddressContext context; - - if (sysprof_address_is_context_switch (address, &context)) - last_context = context; + SysprofSymbol *symbol = symbols[j]; + const char *name; + const char *path; + const char *nick; if (symbol != NULL) - g_print (" %02d: %p: %s [%s]\n", - j, - GSIZE_TO_POINTER (address), - sysprof_symbol_get_name (symbol), - sysprof_symbol_get_binary_path (symbol) ?: ""); + { + name = sysprof_symbol_get_name (symbol); + path = sysprof_symbol_get_binary_path (symbol); + nick = sysprof_symbol_get_binary_nick (symbol); + } else - g_print (" %02d: %p:\n", j, GSIZE_TO_POINTER (address)); + { + name = path = nick = NULL; + } + + g_string_append_printf (str, + " %02d: 0x%"G_GINT64_MODIFIER"x:", + j, + sysprof_document_traceable_get_stack_address (traceable, j)); + + if (name) + g_string_append_printf (str, " %s", name); + + if (path) + g_string_append_printf (str, " [%s]", path); + + if (nick) + g_string_append_printf (str, " (%s)", nick); + + g_string_append_c (str, '\n'); } - g_print (" ================\n"); + g_string_append (str, " ================\n"); + + write (STDOUT_FILENO, str->str, str->len); } g_print ("Document symbolized\n"); @@ -75,10 +100,8 @@ int main (int argc, char *argv[]) { - g_autoptr(SysprofDocument) document = NULL; - g_autoptr(SysprofMultiSymbolizer) multi = NULL; + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(GError) error = NULL; - const char *filename; main_loop = g_main_loop_new (NULL, FALSE); @@ -88,23 +111,8 @@ main (int argc, return 1; } - filename = argv[1]; - - if (!(document = _sysprof_document_new (filename, &error))) - { - g_printerr ("Failed to load document: %s\n", error->message); - return 1; - } - - multi = sysprof_multi_symbolizer_new (); - sysprof_multi_symbolizer_add (multi, sysprof_bundled_symbolizer_new ()); - - _sysprof_document_symbolize_async (document, - SYSPROF_SYMBOLIZER (multi), - NULL, - symbolize_cb, - NULL); - + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_load_async (loader, NULL, load_cb, NULL); g_main_loop_run (main_loop); return 0;