libsysprof-analyze: make SysprofDocumentSymbols private

This instead moves to a public API on the document to symbolize now
that we've gotten much of the necessary bits private in loading the
document. This commit ensures that we only do loading via the loader
now (and removes the incorrect use from the tests so they too go
through the loader).

We check for NoSymbolizer in document symbols so that we can skip any
decoding. That keeps various use cases fast where you don't want to
waste time on symbolizing if you don't need to look at symbols.

There is plenty more we can do to batch decode symbols with some more
API changes, but that will come after we have kernel/userland decoding
integrated from this library.

We may still want to get all symbols into a single symbol cache, but
given that we have address ranges associated with them, that may not
be very useful beyond the hashtable to pid-specific cache we have now.

If symbols were shared between processes, that'd make more sense, but
we aren't doing that (albeit strings are shared between symbol
instances to reduce that overhead).
This commit is contained in:
Christian Hergert
2023-05-12 17:20:10 -07:00
parent ed030d2c25
commit 00ecc41209
18 changed files with 463 additions and 268 deletions

View File

@ -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',

View File

@ -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"

View File

@ -20,8 +20,13 @@
#include "config.h"
#include <errno.h>
#include <unistd.h>
#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));
}
/**

View File

@ -23,24 +23,27 @@
#include <gtk/gtk.h>
#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

View File

@ -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

View File

@ -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;

View File

@ -1,43 +0,0 @@
/*
* sysprof-document-symbols.h
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <glib-object.h>
#include <sysprof-capture.h>
#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

View File

@ -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;
}

View File

@ -25,8 +25,8 @@
#include <sysprof-capture.h>
#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

View File

@ -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));

View File

@ -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)

View File

@ -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;
}

View File

@ -20,18 +20,23 @@
#pragma once
#include <glib-object.h>
#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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) ?: "<unresolved>");
{
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;