Files
sysprof/src/libsysprof-analyze/sysprof-bundled-symbolizer.c
Christian Hergert 64a886eea8 libsysprof-analyze: handle NULL process info
This can happen for "process 0" for example, or anything that was
recorded for a pid which did not get a SysprofCaptureProcess frame.
2023-05-15 14:33:41 -07:00

258 lines
7.6 KiB
C

/* sysprof-bundled-symbolizer.c
*
* 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
*/
#include "config.h"
#include "sysprof-bundled-symbolizer.h"
#include "sysprof-document-private.h"
#include "sysprof-symbolizer-private.h"
#include "sysprof-symbol-private.h"
SYSPROF_ALIGNED_BEGIN(1)
typedef struct
{
SysprofCaptureAddress addr_begin;
SysprofCaptureAddress addr_end;
guint32 pid;
guint32 offset;
guint32 tag_offset;
guint32 padding;
} Decoded
SYSPROF_ALIGNED_END(1);
struct _SysprofBundledSymbolizer
{
SysprofSymbolizer parent_instance;
const Decoded *symbols;
guint n_symbols;
GBytes *bytes;
const gchar *beginptr;
const gchar *endptr;
};
struct _SysprofBundledSymbolizerClass
{
SysprofSymbolizerClass parent_class;
};
G_DEFINE_FINAL_TYPE (SysprofBundledSymbolizer, sysprof_bundled_symbolizer, SYSPROF_TYPE_SYMBOLIZER)
static void
sysprof_bundled_symbolizer_decode (SysprofBundledSymbolizer *self,
GBytes *bytes,
gboolean is_native)
{
char *beginptr;
char *endptr;
g_assert (SYSPROF_IS_BUNDLED_SYMBOLIZER (self));
g_assert (bytes != NULL);
/* Our GBytes always contain a trialing \0 after what we think
* is the end of the buffer.
*/
beginptr = (char *)g_bytes_get_data (bytes, NULL);
endptr = beginptr + g_bytes_get_size (bytes);
for (char *ptr = beginptr;
ptr < endptr && (ptr + sizeof (Decoded)) < endptr;
ptr += sizeof (Decoded))
{
Decoded *sym = (Decoded *)ptr;
if (sym->addr_begin == 0 &&
sym->addr_end == 0 &&
sym->pid == 0 &&
sym->offset == 0)
{
self->symbols = (const Decoded *)beginptr;
self->n_symbols = sym - self->symbols;
break;
}
else if (!is_native)
{
sym->addr_begin = GUINT64_SWAP_LE_BE (sym->addr_begin);
sym->addr_end = GUINT64_SWAP_LE_BE (sym->addr_end);
sym->pid = GUINT32_SWAP_LE_BE (sym->pid);
sym->offset = GUINT32_SWAP_LE_BE (sym->offset);
sym->tag_offset = GUINT32_SWAP_LE_BE (sym->tag_offset);
}
}
self->beginptr = beginptr;
self->endptr = endptr;
self->bytes = g_bytes_ref (bytes);
}
static void
sysprof_bundled_symbolizer_prepare_async (SysprofSymbolizer *symbolizer,
SysprofDocument *document,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
SysprofBundledSymbolizer *self = (SysprofBundledSymbolizer *)symbolizer;
g_autoptr(SysprofDocumentFile) file = NULL;
g_autoptr(GBytes) bytes = NULL;
g_autoptr(GTask) task = NULL;
g_assert (SYSPROF_IS_BUNDLED_SYMBOLIZER (self));
g_assert (SYSPROF_IS_DOCUMENT (document));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_bundled_symbolizer_prepare_async);
if ((file = sysprof_document_lookup_file (document, "__symbols__")) &&
(bytes = sysprof_document_file_dup_bytes (file)))
sysprof_bundled_symbolizer_decode (self, bytes, _sysprof_document_is_native (document));
g_task_return_boolean (task, TRUE);
}
static gboolean
sysprof_bundled_symbolizer_prepare_finish (SysprofSymbolizer *symbolizer,
GAsyncResult *result,
GError **error)
{
g_assert (SYSPROF_IS_BUNDLED_SYMBOLIZER (symbolizer));
g_assert (G_IS_TASK (result));
g_assert (g_task_is_valid (result, symbolizer));
return g_task_propagate_boolean (G_TASK (result), error);
}
static gint
search_for_symbol_cb (gconstpointer a,
gconstpointer b)
{
const Decoded *key = a;
const Decoded *ele = b;
if (key->pid < ele->pid)
return -1;
if (key->pid > ele->pid)
return 1;
g_assert (key->pid == ele->pid);
if (key->addr_begin < ele->addr_begin)
return -1;
if (key->addr_begin >= ele->addr_end)
return 1;
g_assert (key->addr_begin >= ele->addr_begin);
g_assert (key->addr_end <= ele->addr_end);
return 0;
}
static SysprofSymbol *
sysprof_bundled_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
SysprofStrings *strings,
const SysprofProcessInfo *process_info,
SysprofAddressContext context,
SysprofAddress address)
{
SysprofBundledSymbolizer *self = SYSPROF_BUNDLED_SYMBOLIZER (symbolizer);
g_autoptr(GRefString) tag = NULL;
const Decoded *ret;
const Decoded key = {
.addr_begin = address,
.addr_end = address,
.pid = process_info ? process_info->pid : 0,
.offset = 0,
.tag_offset = 0,
};
if (self->n_symbols == 0)
return NULL;
g_assert (self->symbols != NULL);
g_assert (self->n_symbols > 0);
ret = bsearch (&key,
self->symbols,
self->n_symbols,
sizeof (Decoded),
search_for_symbol_cb);
if (ret == NULL || ret->offset == 0)
return NULL;
if (ret->tag_offset > 0)
{
if (ret->tag_offset < (self->endptr - self->beginptr))
tag = sysprof_strings_get (strings, &self->beginptr[ret->tag_offset]);
}
if (ret->offset < (self->endptr - self->beginptr))
return _sysprof_symbol_new (sysprof_strings_get (strings, &self->beginptr[ret->offset]),
NULL,
g_steal_pointer (&tag),
ret->addr_begin,
ret->addr_end);
return NULL;
}
static void
sysprof_bundled_symbolizer_finalize (GObject *object)
{
SysprofBundledSymbolizer *self = (SysprofBundledSymbolizer *)object;
self->symbols = NULL;
self->n_symbols = 0;
self->beginptr = NULL;
self->endptr = NULL;
g_clear_pointer (&self->bytes, g_bytes_unref);
G_OBJECT_CLASS (sysprof_bundled_symbolizer_parent_class)->finalize (object);
}
static void
sysprof_bundled_symbolizer_class_init (SysprofBundledSymbolizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
SysprofSymbolizerClass *symbolizer_class = SYSPROF_SYMBOLIZER_CLASS (klass);
object_class->finalize = sysprof_bundled_symbolizer_finalize;
symbolizer_class->prepare_async = sysprof_bundled_symbolizer_prepare_async;
symbolizer_class->prepare_finish = sysprof_bundled_symbolizer_prepare_finish;
symbolizer_class->symbolize = sysprof_bundled_symbolizer_symbolize;
}
static void
sysprof_bundled_symbolizer_init (SysprofBundledSymbolizer *self)
{
}
SysprofSymbolizer *
sysprof_bundled_symbolizer_new (void)
{
return g_object_new (SYSPROF_TYPE_BUNDLED_SYMBOLIZER, NULL);
}