diff --git a/src/libsysprof-analyze/meson.build b/src/libsysprof-analyze/meson.build index 3b5f72c6..30160e5f 100644 --- a/src/libsysprof-analyze/meson.build +++ b/src/libsysprof-analyze/meson.build @@ -7,6 +7,7 @@ libsysprof_analyze_public_sources = [ 'sysprof-document-file-chunk.c', 'sysprof-document-fork.c', 'sysprof-document-frame.c', + 'sysprof-document-jitmap.c', 'sysprof-document-loader.c', 'sysprof-document-log.c', 'sysprof-document-mark.c', @@ -51,6 +52,7 @@ libsysprof_analyze_public_headers = [ 'sysprof-document-file-chunk.h', 'sysprof-document-fork.h', 'sysprof-document-frame.h', + 'sysprof-document-jitmap.h', 'sysprof-document-loader.h', 'sysprof-document-log.h', 'sysprof-document-mark.h', diff --git a/src/libsysprof-analyze/sysprof-analyze.h b/src/libsysprof-analyze/sysprof-analyze.h index 3e2b186d..68c32272 100644 --- a/src/libsysprof-analyze/sysprof-analyze.h +++ b/src/libsysprof-analyze/sysprof-analyze.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS # include "sysprof-document-fork.h" # include "sysprof-document-frame.h" # include "sysprof-document-loader.h" +# include "sysprof-document-jitmap.h" # include "sysprof-document-log.h" # include "sysprof-document-mark.h" # include "sysprof-document-metadata.h" diff --git a/src/libsysprof-analyze/sysprof-document-frame-private.h b/src/libsysprof-analyze/sysprof-document-frame-private.h index 91a74a8a..50326fe9 100644 --- a/src/libsysprof-analyze/sysprof-document-frame-private.h +++ b/src/libsysprof-analyze/sysprof-document-frame-private.h @@ -46,6 +46,9 @@ SysprofDocumentFrame *_sysprof_document_frame_new (GMappedFile *ma guint16 frame_len, gboolean needs_swap); +#define SYSPROF_DOCUMENT_FRAME_ENDPTR(obj) \ + (&((const guint8 *)SYSPROF_DOCUMENT_FRAME(obj)->frame)[SYSPROF_DOCUMENT_FRAME(obj)->frame_len]) + #define SYSPROF_DOCUMENT_FRAME_GET(obj, type) \ ((const type *)(SYSPROF_DOCUMENT_FRAME(obj)->frame)) diff --git a/src/libsysprof-analyze/sysprof-document-frame.c b/src/libsysprof-analyze/sysprof-document-frame.c index 6dbab9f6..09664eab 100644 --- a/src/libsysprof-analyze/sysprof-document-frame.c +++ b/src/libsysprof-analyze/sysprof-document-frame.c @@ -27,6 +27,7 @@ #include "sysprof-document-file-chunk.h" #include "sysprof-document-fork.h" #include "sysprof-document-log.h" +#include "sysprof-document-jitmap.h" #include "sysprof-document-mark.h" #include "sysprof-document-mmap.h" #include "sysprof-document-overlay.h" @@ -173,6 +174,10 @@ _sysprof_document_frame_new (GMappedFile *mapped_file, gtype = SYSPROF_TYPE_DOCUMENT_OVERLAY; break; + case SYSPROF_CAPTURE_FRAME_JITMAP: + gtype = SYSPROF_TYPE_DOCUMENT_JITMAP; + break; + default: gtype = SYSPROF_TYPE_DOCUMENT_FRAME; break; diff --git a/src/libsysprof-analyze/sysprof-document-jitmap.c b/src/libsysprof-analyze/sysprof-document-jitmap.c new file mode 100644 index 00000000..d4ac04f6 --- /dev/null +++ b/src/libsysprof-analyze/sysprof-document-jitmap.c @@ -0,0 +1,166 @@ +/* sysprof-document-jitmap.c + * + * 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 + */ + +#include "config.h" + +#include "sysprof-document-frame-private.h" +#include "sysprof-document-jitmap.h" + +typedef struct _Jitmap +{ + SysprofAddress address; + const char *name; +} Jitmap; + +struct _SysprofDocumentJitmap +{ + SysprofDocumentFrame parent_instance; + GArray *jitmaps; + guint initialized : 1; +}; + +struct _SysprofDocumentJitmapClass +{ + SysprofDocumentFrameClass parent_class; +}; + +enum { + PROP_0, + PROP_SIZE, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofDocumentJitmap, sysprof_document_jitmap, SYSPROF_TYPE_DOCUMENT_FRAME) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_document_jitmap_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofDocumentJitmap *self = SYSPROF_DOCUMENT_JITMAP (object); + + switch (prop_id) + { + case PROP_SIZE: + g_value_set_uint (value, sysprof_document_jitmap_get_size (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_document_jitmap_class_init (SysprofDocumentJitmapClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = sysprof_document_jitmap_get_property; + + properties [PROP_SIZE] = + g_param_spec_string ("size", NULL, NULL, + NULL, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_document_jitmap_init (SysprofDocumentJitmap *self) +{ + self->jitmaps = g_array_new (FALSE, FALSE, sizeof (Jitmap)); +} + +guint +sysprof_document_jitmap_get_size (SysprofDocumentJitmap *self) +{ + const SysprofCaptureJitmap *jitmap; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_JITMAP (self), 0); + + jitmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureJitmap); + + return SYSPROF_DOCUMENT_FRAME_UINT32 (self, jitmap->n_jitmaps); +} + +/** + * sysprof_document_jitmap_get_mapping: + * @self: a #SysprofDocumentJitmap + * @nth: the index of the mapping + * @address: (out): a location for the address + * + * Gets the @nth mapping and returns it as @address and the return value + * of this function. + * + * Returns: (nullable): the name of the symbol, or %NULL if @nth is + * out of bounds. + */ +const char * +sysprof_document_jitmap_get_mapping (SysprofDocumentJitmap *self, + guint nth, + SysprofAddress *address) +{ + const SysprofCaptureJitmap *frame; + const Jitmap *j; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_JITMAP (self), NULL); + g_return_val_if_fail (address != NULL, NULL); + + if G_UNLIKELY (!self->initialized) + { + const guint8 *pos; + const guint8 *endptr; + + self->initialized = TRUE; + + frame = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureJitmap); + endptr = SYSPROF_DOCUMENT_FRAME_ENDPTR (self); + pos = frame->data; + + while (pos < endptr) + { + Jitmap map; + + if (pos + sizeof map.address >= endptr) + break; + + memcpy (&map.address, pos, sizeof map.address); + pos += sizeof map.address; + + if (!(map.name = SYSPROF_DOCUMENT_FRAME_CSTRING (self, (const char *)pos))) + break; + + pos += strlen (map.name) + 1; + + g_array_append_val (self->jitmaps, map); + } + } + + if (nth >= self->jitmaps->len) + return NULL; + + j = &g_array_index (self->jitmaps, Jitmap, nth); + *address = j->address; + return j->name; +} + diff --git a/src/libsysprof-analyze/sysprof-document-jitmap.h b/src/libsysprof-analyze/sysprof-document-jitmap.h new file mode 100644 index 00000000..f6b83543 --- /dev/null +++ b/src/libsysprof-analyze/sysprof-document-jitmap.h @@ -0,0 +1,49 @@ +/* sysprof-document-jitmap.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 "sysprof-document-frame.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_DOCUMENT_JITMAP (sysprof_document_jitmap_get_type()) +#define SYSPROF_IS_DOCUMENT_JITMAP(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_JITMAP) +#define SYSPROF_DOCUMENT_JITMAP(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_JITMAP, SysprofDocumentJitmap) +#define SYSPROF_DOCUMENT_JITMAP_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_JITMAP, SysprofDocumentJitmapClass) + +typedef struct _SysprofDocumentJitmap SysprofDocumentJitmap; +typedef struct _SysprofDocumentJitmapClass SysprofDocumentJitmapClass; + +SYSPROF_AVAILABLE_IN_ALL +GType sysprof_document_jitmap_get_type (void) G_GNUC_CONST; +SYSPROF_AVAILABLE_IN_ALL +guint sysprof_document_jitmap_get_size (SysprofDocumentJitmap *self); +SYSPROF_AVAILABLE_IN_ALL +const char *sysprof_document_jitmap_get_mapping (SysprofDocumentJitmap *self, + guint position, + SysprofAddress *address); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentJitmap, g_object_unref) + +G_END_DECLS + diff --git a/src/libsysprof-analyze/tests/meson.build b/src/libsysprof-analyze/tests/meson.build index c57a231a..5220419c 100644 --- a/src/libsysprof-analyze/tests/meson.build +++ b/src/libsysprof-analyze/tests/meson.build @@ -15,6 +15,7 @@ libsysprof_analyze_testsuite = { 'test-capture-model' : {'skip': true}, 'test-elf-loader' : {'skip': true}, 'test-list-files' : {'skip': true}, + 'test-list-jitmap' : {'skip': true}, 'test-print-file' : {'skip': true}, 'test-list-processes' : {'skip': true}, 'test-list-address-layout' : {'skip': true}, diff --git a/src/libsysprof-analyze/tests/test-capture-model.c b/src/libsysprof-analyze/tests/test-capture-model.c index ae47bf4d..aa5dd0f9 100644 --- a/src/libsysprof-analyze/tests/test-capture-model.c +++ b/src/libsysprof-analyze/tests/test-capture-model.c @@ -81,6 +81,9 @@ main (int argc, sysprof_document_mmap_get_end_address (SYSPROF_DOCUMENT_MMAP (frame)), sysprof_document_mmap_get_file_offset (SYSPROF_DOCUMENT_MMAP (frame)), sysprof_document_mmap_get_file (SYSPROF_DOCUMENT_MMAP (frame))); + else if (SYSPROF_IS_DOCUMENT_JITMAP (frame)) + g_print (" n_jitmaps=%u", + sysprof_document_jitmap_get_size (SYSPROF_DOCUMENT_JITMAP (frame))); else if (SYSPROF_IS_DOCUMENT_ALLOCATION (frame)) { if (sysprof_document_allocation_is_free (SYSPROF_DOCUMENT_ALLOCATION (frame))) diff --git a/src/libsysprof-analyze/tests/test-list-jitmap.c b/src/libsysprof-analyze/tests/test-list-jitmap.c new file mode 100644 index 00000000..ea1703b1 --- /dev/null +++ b/src/libsysprof-analyze/tests/test-list-jitmap.c @@ -0,0 +1,74 @@ +/* test-list-jitmap.c + * + * 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 + */ + +#include + +#include "sysprof-document-private.h" + +int +main (int argc, + char *argv[]) +{ + g_autoptr(SysprofDocumentLoader) loader = NULL; + g_autoptr(SysprofDocument) document = NULL; + g_autoptr(GError) error = NULL; + guint n_items; + + if (argc < 2) + { + g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]); + return 1; + } + + 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; + } + + n_items = g_list_model_get_n_items (G_LIST_MODEL (document)); + + for (guint i = 0; i < n_items; i++) + { + g_autoptr(SysprofDocumentFrame) frame = g_list_model_get_item ((GListModel *)document, i); + + if (SYSPROF_IS_DOCUMENT_JITMAP (frame)) + { + SysprofDocumentJitmap *jitmap = SYSPROF_DOCUMENT_JITMAP (frame); + guint size = sysprof_document_jitmap_get_size (jitmap); + + for (guint j = 0; j < size; j++) + { + SysprofAddress address; + const char *name; + + if (!(name = sysprof_document_jitmap_get_mapping (jitmap, j, &address))) + break; + + g_print ("0x%"G_GINT64_MODIFIER"x: %s\n", address, name); + } + } + } + + return 0; +}