Compare commits

...

No commits in common. "c9-beta" and "c10s" have entirely different histories.

39 changed files with 8534 additions and 468 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
SOURCES/sysprof-3.40.1.tar.xz /sysprof-*.tar.xz
/libunwind-1.8.1.tar.gz

View File

@ -1 +0,0 @@
a2c1e951c4332a4efb0c702025d896ca175bb6fa SOURCES/sysprof-3.40.1.tar.xz

View File

@ -0,0 +1,42 @@
From 86cd5222dc05e81305ffb22a49cb453c2f90e055 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 16:11:47 -0800
Subject: [PATCH 01/31] build: add 47 version macros
---
src/libsysprof-capture/sysprof-version-macros.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/libsysprof-capture/sysprof-version-macros.h b/src/libsysprof-capture/sysprof-version-macros.h
index 67dac287..d11b6bc9 100644
--- a/src/libsysprof-capture/sysprof-version-macros.h
+++ b/src/libsysprof-capture/sysprof-version-macros.h
@@ -91,6 +91,7 @@
#define SYSPROF_VERSION_3_38 (SYSPROF_ENCODE_VERSION (3, 38, 0))
#define SYSPROF_VERSION_3_40 (SYSPROF_ENCODE_VERSION (3, 40, 0))
#define SYSPROF_VERSION_3_46 (SYSPROF_ENCODE_VERSION (3, 46, 0))
+#define SYSPROF_VERSION_47 (SYSPROF_ENCODE_VERSION (47, 0, 0))
#if (SYSPROF_MINOR_VERSION == 99)
# define SYSPROF_VERSION_CUR_STABLE (SYSPROF_ENCODE_VERSION (SYSPROF_MAJOR_VERSION + 1, 0, 0))
@@ -232,3 +233,17 @@
#else
# define SYSPROF_AVAILABLE_IN_3_46 _SYSPROF_EXTERN
#endif
+
+#if SYSPROF_VERSION_MIN_REQUIRED >= SYSPROF_VERSION_47
+# define SYSPROF_DEPRECATED_IN_47 SYSPROF_DEPRECATED
+# define SYSPROF_DEPRECATED_IN_47_FOR(f) SYSPROF_DEPRECATED_FOR(f)
+#else
+# define SYSPROF_DEPRECATED_IN_47 _SYSPROF_EXTERN
+# define SYSPROF_DEPRECATED_IN_47_FOR(f) _SYSPROF_EXTERN
+#endif
+
+#if SYSPROF_VERSION_MAX_ALLOWED < SYSPROF_VERSION_47
+# define SYSPROF_AVAILABLE_IN_47 SYSPROF_UNAVAILABLE(47, 0)
+#else
+# define SYSPROF_AVAILABLE_IN_47 _SYSPROF_EXTERN
+#endif
--
2.45.2

View File

@ -0,0 +1,28 @@
From c7910ee7b9f8d2b15f0b05f33e2280e3861ba9fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= <pobrn@protonmail.com>
Date: Wed, 9 Oct 2024 15:29:59 +0200
Subject: [PATCH 02/31] libsysprof: elf: do not allow setting self as debug
link
That will cause infinite recursion in `sysprof_elf_get_symbol_at_address_internal()`.
Also note that loops are still possible, this change
only prevents one way of creating loops.
---
src/libsysprof/sysprof-elf.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/libsysprof/sysprof-elf.c b/src/libsysprof/sysprof-elf.c
index f4e5f914..0534eccb 100644
--- a/src/libsysprof/sysprof-elf.c
+++ b/src/libsysprof/sysprof-elf.c
@@ -502,6 +502,7 @@ sysprof_elf_set_debug_link_elf (SysprofElf *self,
{
g_return_if_fail (SYSPROF_IS_ELF (self));
g_return_if_fail (!debug_link_elf || SYSPROF_IS_ELF (debug_link_elf));
+ g_return_if_fail (debug_link_elf != self);
if (g_set_object (&self->debug_link_elf, debug_link_elf))
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUG_LINK_ELF]);
--
2.45.2

View File

@ -0,0 +1,140 @@
From 8a8b5b25ff8cb9119fc781ea686826723c93d2ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= <pobrn@protonmail.com>
Date: Wed, 9 Oct 2024 15:28:14 +0200
Subject: [PATCH 03/31] libsysprof: elf: do not generate fallback names
Fallback names are only used in `SysprofElfSymbolizer` at the
moment, but it also has code to generate fallback symbols.
---
src/libsysprof/sysprof-elf-private.h | 3 +--
src/libsysprof/sysprof-elf-symbolizer.c | 12 ++++++------
src/libsysprof/sysprof-elf.c | 17 +++++------------
3 files changed, 12 insertions(+), 20 deletions(-)
diff --git a/src/libsysprof/sysprof-elf-private.h b/src/libsysprof/sysprof-elf-private.h
index b4d0f737..146bc2de 100644
--- a/src/libsysprof/sysprof-elf-private.h
+++ b/src/libsysprof/sysprof-elf-private.h
@@ -42,8 +42,7 @@ const char *sysprof_elf_get_debug_link (SysprofElf *self);
char *sysprof_elf_get_symbol_at_address (SysprofElf *self,
guint64 address,
guint64 *begin_address,
- guint64 *end_address,
- gboolean *is_fallback);
+ guint64 *end_address);
SysprofElf *sysprof_elf_get_debug_link_elf (SysprofElf *self);
void sysprof_elf_set_debug_link_elf (SysprofElf *self,
SysprofElf *debug_link_elf);
diff --git a/src/libsysprof/sysprof-elf-symbolizer.c b/src/libsysprof/sysprof-elf-symbolizer.c
index 8fdf204f..f7aabef7 100644
--- a/src/libsysprof/sysprof-elf-symbolizer.c
+++ b/src/libsysprof/sysprof-elf-symbolizer.c
@@ -61,9 +61,9 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
g_autoptr(SysprofElf) elf = NULL;
SysprofDocumentMmap *map;
g_autofree char *name = NULL;
+ const char *nick = NULL;
const char *path;
const char *build_id;
- gboolean is_fallback = FALSE;
guint64 map_begin;
guint64 map_end;
guint64 relative_address;
@@ -115,14 +115,15 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
NULL)))
goto fallback;
+ nick = sysprof_elf_get_nick (elf);
+
/* Try to get the symbol name at the address and the begin/end address
* so that it can be inserted into our symbol cache.
*/
if (!(name = sysprof_elf_get_symbol_at_address (elf,
relative_address,
&begin_address,
- &end_address,
- &is_fallback)))
+ &end_address)))
goto fallback;
/* Sanitize address ranges if we have to. Sometimes that can happen
@@ -135,11 +136,10 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
sysprof_strings_get (strings, path),
- sysprof_strings_get (strings, sysprof_elf_get_nick (elf)),
+ sysprof_strings_get (strings, nick),
map_begin + (begin_address - file_offset),
map_begin + (end_address - file_offset),
SYSPROF_SYMBOL_KIND_USER);
- ret->is_fallback = is_fallback;
return ret;
@@ -156,7 +156,7 @@ fallback:
ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
sysprof_strings_get (strings, path),
- NULL,
+ sysprof_strings_get (strings, nick),
begin_address, end_address,
SYSPROF_SYMBOL_KIND_USER);
ret->is_fallback = TRUE;
diff --git a/src/libsysprof/sysprof-elf.c b/src/libsysprof/sysprof-elf.c
index 0534eccb..df73ce6d 100644
--- a/src/libsysprof/sysprof-elf.c
+++ b/src/libsysprof/sysprof-elf.c
@@ -409,8 +409,7 @@ sysprof_elf_get_symbol_at_address_internal (SysprofElf *self,
guint64 address,
guint64 *begin_address,
guint64 *end_address,
- guint64 text_offset,
- gboolean *is_fallback)
+ guint64 text_offset)
{
const ElfSym *symbol;
char *ret = NULL;
@@ -421,7 +420,7 @@ sysprof_elf_get_symbol_at_address_internal (SysprofElf *self,
if (self->debug_link_elf != NULL)
{
- ret = sysprof_elf_get_symbol_at_address_internal (self->debug_link_elf, filename, address, begin_address, end_address, text_offset, is_fallback);
+ ret = sysprof_elf_get_symbol_at_address_internal (self->debug_link_elf, filename, address, begin_address, end_address, text_offset);
if (ret != NULL)
return ret;
@@ -447,11 +446,7 @@ sysprof_elf_get_symbol_at_address_internal (SysprofElf *self,
}
else
{
- begin = address;
- end = address + 1;
- ret = g_strdup_printf ("In File %s+0x%"G_GINT64_MODIFIER"x", filename, address);
- if (is_fallback)
- *is_fallback = TRUE;
+ return NULL;
}
if (begin_address)
@@ -467,16 +462,14 @@ char *
sysprof_elf_get_symbol_at_address (SysprofElf *self,
guint64 address,
guint64 *begin_address,
- guint64 *end_address,
- gboolean *is_fallback)
+ guint64 *end_address)
{
return sysprof_elf_get_symbol_at_address_internal (self,
self->file,
address,
begin_address,
end_address,
- self->text_offset,
- is_fallback);
+ self->text_offset);
}
/**
--
2.45.2

View File

@ -0,0 +1,53 @@
From 5fc61b27c750788e23f41ed2e87c99cca0dedd9c Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 9 Oct 2024 16:39:13 -0700
Subject: [PATCH 04/31] sysprof: update to AdwSpinner
---
src/sysprof/meson.build | 2 +-
src/sysprof/sysprof-window.ui | 9 +--------
2 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build
index ccd698ea..989bbd11 100644
--- a/src/sysprof/meson.build
+++ b/src/sysprof/meson.build
@@ -85,7 +85,7 @@ sysprof_resources = gnome.compile_resources('sysprof-resources', 'sysprof.gresou
sysprof_deps = [
cc.find_library('m', required: false),
dependency('gtk4', version: gtk_req_version),
- dependency('libadwaita-1', version: '>= 1.6.alpha'),
+ dependency('libadwaita-1', version: '>= 1.6.0'),
dependency('libpanel-1', version: '>= 1.7.0'),
libsysprof_static_dep,
diff --git a/src/sysprof/sysprof-window.ui b/src/sysprof/sysprof-window.ui
index b33cd613..1b361e37 100644
--- a/src/sysprof/sysprof-window.ui
+++ b/src/sysprof/sysprof-window.ui
@@ -109,7 +109,7 @@
<property name="title-widget">
<object class="GtkCenterBox">
<child type="start">
- <object class="GtkSpinner">
+ <object class="AdwSpinner">
<binding name="visible">
<lookup name="busy" type="SysprofDocument">
<lookup name="document" type="SysprofSession">
@@ -117,13 +117,6 @@
</lookup>
</lookup>
</binding>
- <binding name="spinning">
- <lookup name="busy" type="SysprofDocument">
- <lookup name="document" type="SysprofSession">
- <lookup name="session">SysprofWindow</lookup>
- </lookup>
- </lookup>
- </binding>
</object>
</child>
<child type="center">
--
2.45.2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,120 @@
From 3633d7b645c4db819cf2263ae32fa63b413c5eb9 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Thu, 10 Oct 2024 17:03:30 -0700
Subject: [PATCH 06/31] libsysprof: add setup hooks for symbolizers
This gives the symbolizer access to the loader so we can propagate tasks
back to it.
---
src/libsysprof/sysprof-multi-symbolizer.c | 22 +++++++++++++++++++++
src/libsysprof/sysprof-symbolizer-private.h | 6 +++++-
src/libsysprof/sysprof-symbolizer.c | 11 +++++++++++
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/src/libsysprof/sysprof-multi-symbolizer.c b/src/libsysprof/sysprof-multi-symbolizer.c
index 483cdde5..e1ad90b0 100644
--- a/src/libsysprof/sysprof-multi-symbolizer.c
+++ b/src/libsysprof/sysprof-multi-symbolizer.c
@@ -27,6 +27,7 @@ struct _SysprofMultiSymbolizer
{
SysprofSymbolizer parent_instance;
GPtrArray *symbolizers;
+ guint frozen : 1;
};
struct _SysprofMultiSymbolizerClass
@@ -138,6 +139,25 @@ sysprof_multi_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
return NULL;
}
+static void
+sysprof_multi_symbolizer_setup (SysprofSymbolizer *symbolizer,
+ SysprofDocumentLoader *loader)
+{
+ SysprofMultiSymbolizer *self = (SysprofMultiSymbolizer *)symbolizer;
+
+ g_assert (SYSPROF_IS_MULTI_SYMBOLIZER (self));
+ g_assert (SYSPROF_IS_DOCUMENT_LOADER (loader));
+
+ self->frozen = TRUE;
+
+ for (guint i = 0; i < self->symbolizers->len; i++)
+ {
+ SysprofSymbolizer *child = g_ptr_array_index (self->symbolizers, i);
+
+ _sysprof_symbolizer_setup (child, loader);
+ }
+}
+
static void
sysprof_multi_symbolizer_finalize (GObject *object)
{
@@ -159,6 +179,7 @@ sysprof_multi_symbolizer_class_init (SysprofMultiSymbolizerClass *klass)
symbolizer_class->prepare_async = sysprof_multi_symbolizer_prepare_async;
symbolizer_class->prepare_finish = sysprof_multi_symbolizer_prepare_finish;
symbolizer_class->symbolize = sysprof_multi_symbolizer_symbolize;
+ symbolizer_class->setup = sysprof_multi_symbolizer_setup;
}
static void
@@ -188,6 +209,7 @@ sysprof_multi_symbolizer_take (SysprofMultiSymbolizer *self,
g_return_if_fail (SYSPROF_IS_MULTI_SYMBOLIZER (self));
g_return_if_fail (SYSPROF_IS_SYMBOLIZER (symbolizer));
g_return_if_fail ((gpointer)self != (gpointer)symbolizer);
+ g_return_if_fail (self->frozen == FALSE);
g_ptr_array_add (self->symbolizers, symbolizer);
}
diff --git a/src/libsysprof/sysprof-symbolizer-private.h b/src/libsysprof/sysprof-symbolizer-private.h
index dd917e44..3d68c52b 100644
--- a/src/libsysprof/sysprof-symbolizer-private.h
+++ b/src/libsysprof/sysprof-symbolizer-private.h
@@ -22,6 +22,7 @@
#include "sysprof-address-layout-private.h"
#include "sysprof-document.h"
+#include "sysprof-document-loader.h"
#include "sysprof-mount-namespace-private.h"
#include "sysprof-process-info-private.h"
#include "sysprof-strings-private.h"
@@ -41,6 +42,8 @@ struct _SysprofSymbolizerClass
{
GObjectClass parent_class;
+ void (*setup) (SysprofSymbolizer *self,
+ SysprofDocumentLoader *loader);
void (*prepare_async) (SysprofSymbolizer *self,
SysprofDocument *document,
GCancellable *cancellable,
@@ -56,7 +59,8 @@ struct _SysprofSymbolizerClass
SysprofAddress address);
};
-
+void _sysprof_symbolizer_setup (SysprofSymbolizer *self,
+ SysprofDocumentLoader *loader);
void _sysprof_symbolizer_prepare_async (SysprofSymbolizer *self,
SysprofDocument *document,
GCancellable *cancellable,
diff --git a/src/libsysprof/sysprof-symbolizer.c b/src/libsysprof/sysprof-symbolizer.c
index 9ad17ca2..47d6021a 100644
--- a/src/libsysprof/sysprof-symbolizer.c
+++ b/src/libsysprof/sysprof-symbolizer.c
@@ -99,3 +99,14 @@ _sysprof_symbolizer_symbolize (SysprofSymbolizer *self,
{
return SYSPROF_SYMBOLIZER_GET_CLASS (self)->symbolize (self, strings, process_info, context, address);
}
+
+void
+_sysprof_symbolizer_setup (SysprofSymbolizer *self,
+ SysprofDocumentLoader *loader)
+{
+ g_return_if_fail (SYSPROF_IS_SYMBOLIZER (self));
+ g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (loader));
+
+ if (SYSPROF_SYMBOLIZER_GET_CLASS (self)->setup)
+ SYSPROF_SYMBOLIZER_GET_CLASS (self)->setup (self, loader);
+}
--
2.45.2

View File

@ -0,0 +1,159 @@
From 271b9abbbca3b334f95cb70141fac9ad2452f3f5 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Thu, 10 Oct 2024 17:04:19 -0700
Subject: [PATCH 07/31] libsysprof: hoist fallback symbol creation
This makes sure that we get that even when not using the Elf symbolizer
but also means we can fallback through the Elf symbolizer into the
debuginfod symbolizer.
---
src/libsysprof/sysprof-document-symbols.c | 69 ++++++++++++++++++++++-
src/libsysprof/sysprof-elf-symbolizer.c | 24 +-------
2 files changed, 69 insertions(+), 24 deletions(-)
diff --git a/src/libsysprof/sysprof-document-symbols.c b/src/libsysprof/sysprof-document-symbols.c
index 2f8d1849..828c7fb6 100644
--- a/src/libsysprof/sysprof-document-symbols.c
+++ b/src/libsysprof/sysprof-document-symbols.c
@@ -85,6 +85,71 @@ symbolize_free (Symbolize *state)
g_free (state);
}
+static SysprofSymbol *
+do_symbolize (SysprofSymbolizer *symbolizer,
+ SysprofStrings *strings,
+ SysprofProcessInfo *process_info,
+ SysprofAddressContext last_context,
+ SysprofAddress address)
+{
+ SysprofDocumentMmap *map;
+ g_autofree char *name = NULL;
+ SysprofSymbol *ret;
+ const char *nick = NULL;
+ const char *path;
+ guint64 map_begin;
+ guint64 map_end;
+ guint64 relative_address;
+ guint64 begin_address;
+ guint64 end_address;
+ guint64 file_offset;
+
+ if ((ret = _sysprof_symbolizer_symbolize (symbolizer, strings, process_info, last_context, address)))
+ return ret;
+
+ /* Fallback, we failed to locate the symbol within a file we can
+ * access, so tell the user about what file contained the symbol
+ * and where (relative to that file) the IP was.
+ */
+
+ if (!(map = sysprof_address_layout_lookup (process_info->address_layout, address)))
+ return NULL;
+
+ map_begin = sysprof_document_mmap_get_start_address (map);
+ map_end = sysprof_document_mmap_get_end_address (map);
+
+ g_assert (address >= map_begin);
+ g_assert (address < map_end);
+
+ file_offset = sysprof_document_mmap_get_file_offset (map);
+
+ relative_address = address;
+ relative_address -= map_begin;
+ relative_address += file_offset;
+
+ path = sysprof_document_mmap_get_file (map);
+
+ begin_address = CLAMP (begin_address, file_offset, file_offset + (map_end - map_begin));
+ end_address = CLAMP (end_address, file_offset, file_offset + (map_end - map_begin));
+ if (end_address == begin_address)
+ end_address++;
+
+ name = g_strdup_printf ("In File %s+0x%"G_GINT64_MODIFIER"x",
+ sysprof_document_mmap_get_file (map),
+ relative_address);
+ begin_address = address;
+ end_address = address + 1;
+
+ ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
+ sysprof_strings_get (strings, path),
+ sysprof_strings_get (strings, nick),
+ begin_address, end_address,
+ SYSPROF_SYMBOL_KIND_USER);
+ ret->is_fallback = TRUE;
+
+ return ret;
+}
+
static void
add_traceable (SysprofDocumentSymbols *self,
SysprofStrings *strings,
@@ -123,7 +188,7 @@ add_traceable (SysprofDocumentSymbols *self,
if (sysprof_symbol_cache_lookup (self->kernel_symbols, address) != NULL)
continue;
- if ((symbol = _sysprof_symbolizer_symbolize (symbolizer, strings, process_info, last_context, address)))
+ if ((symbol = do_symbolize (symbolizer, strings, process_info, last_context, address)))
sysprof_symbol_cache_take (self->kernel_symbols, g_steal_pointer (&symbol));
}
else
@@ -134,7 +199,7 @@ add_traceable (SysprofDocumentSymbols *self,
sysprof_symbol_cache_lookup (process_info->symbol_cache, address) != NULL)
continue;
- if ((symbol = _sysprof_symbolizer_symbolize (symbolizer, strings, process_info, last_context, address)))
+ if ((symbol = do_symbolize (symbolizer, strings, process_info, last_context, address)))
sysprof_symbol_cache_take (process_info->symbol_cache, g_steal_pointer (&symbol));
}
}
diff --git a/src/libsysprof/sysprof-elf-symbolizer.c b/src/libsysprof/sysprof-elf-symbolizer.c
index f7aabef7..05bd1d6c 100644
--- a/src/libsysprof/sysprof-elf-symbolizer.c
+++ b/src/libsysprof/sysprof-elf-symbolizer.c
@@ -113,7 +113,7 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
build_id,
file_inode,
NULL)))
- goto fallback;
+ return NULL;
nick = sysprof_elf_get_nick (elf);
@@ -124,7 +124,7 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
relative_address,
&begin_address,
&end_address)))
- goto fallback;
+ return NULL;
/* Sanitize address ranges if we have to. Sometimes that can happen
* for us, but it seems to be limited to glibc.
@@ -142,26 +142,6 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
SYSPROF_SYMBOL_KIND_USER);
return ret;
-
-fallback:
- /* Fallback, we failed to locate the symbol within a file we can
- * access, so tell the user about what file contained the symbol
- * and where (relative to that file) the IP was.
- */
- name = g_strdup_printf ("In File %s+0x%"G_GINT64_MODIFIER"x",
- sysprof_document_mmap_get_file (map),
- relative_address);
- begin_address = address;
- end_address = address + 1;
-
- ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
- sysprof_strings_get (strings, path),
- sysprof_strings_get (strings, nick),
- begin_address, end_address,
- SYSPROF_SYMBOL_KIND_USER);
- ret->is_fallback = TRUE;
-
- return ret;
}
static void
--
2.45.2

View File

@ -0,0 +1,600 @@
From 18f01748814e558f3b2754ef9c541e8e4b2b3fb0 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Thu, 10 Oct 2024 17:07:21 -0700
Subject: [PATCH 08/31] libsysprof: add debuginfod symbolizer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is based on a debuginfod_client provided by Barnabás Pőcze in !73.
It extends it to use the new task infrastructure to elevate the download
process to the user while loading a capture file.
---
config.h.meson | 2 +
meson.build | 2 +
meson_options.txt | 2 +
src/libsysprof/meson.build | 8 +
.../sysprof-debuginfod-symbolizer.c | 229 ++++++++++++++++++
.../sysprof-debuginfod-symbolizer.h | 42 ++++
.../sysprof-debuginfod-task-private.h | 42 ++++
src/libsysprof/sysprof-debuginfod-task.c | 131 ++++++++++
src/libsysprof/sysprof-document-loader.c | 15 +-
9 files changed, 468 insertions(+), 5 deletions(-)
create mode 100644 src/libsysprof/sysprof-debuginfod-symbolizer.c
create mode 100644 src/libsysprof/sysprof-debuginfod-symbolizer.h
create mode 100644 src/libsysprof/sysprof-debuginfod-task-private.h
create mode 100644 src/libsysprof/sysprof-debuginfod-task.c
diff --git a/config.h.meson b/config.h.meson
index d2f7589a..48b3c2c2 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -16,6 +16,8 @@
#mesondefine HAVE_LIBSYSTEMD
+#mesondefine HAVE_DEBUGINFOD
+
#mesondefine HAVE_PERF_CLOCKID
#mesondefine HAVE_POLKIT
diff --git a/meson.build b/meson.build
index 96c1d093..bac8eae6 100644
--- a/meson.build
+++ b/meson.build
@@ -63,6 +63,7 @@ gio_unix_dep = dependency('gio-unix-2.0', version: glib_req_version,
required: need_glib and host_machine.system() != 'windows')
gtk_dep = dependency('gtk4', version: gtk_req_version, required: need_gtk)
libsystemd_dep = dependency('libsystemd', required: false)
+debuginfod_dep = dependency('libdebuginfod', required: get_option('debuginfod'))
config_h = configuration_data()
config_h.set_quoted('API_VERSION_S', libsysprof_api_version.to_string())
@@ -99,6 +100,7 @@ config_h.set10('ENABLE_NLS', true)
config_h.set_quoted('GETTEXT_PACKAGE', 'sysprof')
config_h.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
config_h.set10('HAVE_LIBSYSTEMD', libsystemd_dep.found())
+config_h.set10('HAVE_DEBUGINFOD', debuginfod_dep.found())
polkit_agent_dep = dependency('polkit-agent-1', required: get_option('polkit-agent'))
config_h.set10('HAVE_POLKIT_AGENT', polkit_agent_dep.found())
diff --git a/meson_options.txt b/meson_options.txt
index 2f78fc3b..02bb6981 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -49,3 +49,5 @@ option('tests', type: 'boolean')
# Optionally disable the examples (this is mostly only useful for building only
# libsysprof-capture as a subproject)
option('examples', type: 'boolean')
+
+option('debuginfod', type: 'feature')
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index 697e9665..b4e58078 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -153,6 +153,13 @@ libsysprof_private_sources = [
'timsort/gtktimsort.c',
]
+if debuginfod_dep.found() and get_option('debuginfod').enabled()
+ libsysprof_private_sources += [
+ 'sysprof-debuginfod-symbolizer.c',
+ 'sysprof-debuginfod-task.c'
+ ]
+endif
+
if polkit_dep.found()
libsysprof_private_sources += ['sysprof-polkit.c']
endif
@@ -192,6 +199,7 @@ libsysprof_deps = [
libsystemd_dep,
polkit_dep,
+ debuginfod_dep,
libeggbitset_static_dep,
libelfparser_static_dep,
diff --git a/src/libsysprof/sysprof-debuginfod-symbolizer.c b/src/libsysprof/sysprof-debuginfod-symbolizer.c
new file mode 100644
index 00000000..8dd60d19
--- /dev/null
+++ b/src/libsysprof/sysprof-debuginfod-symbolizer.c
@@ -0,0 +1,229 @@
+/* sysprof-debuginfod-symbolizer.c
+ *
+ * Copyright 2024 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 <elfutils/debuginfod.h>
+#include <errno.h>
+#include <stdatomic.h>
+
+#include <glib/gstdio.h>
+
+#include "sysprof-symbolizer-private.h"
+#include "sysprof-debuginfod-symbolizer.h"
+#include "sysprof-debuginfod-task-private.h"
+#include "sysprof-elf-loader-private.h"
+#include "sysprof-symbol-private.h"
+
+struct _SysprofDebuginfodSymbolizer
+{
+ SysprofSymbolizer parent_instance;
+
+ GWeakRef loader_wr;
+
+ debuginfod_client *client;
+ SysprofElfLoader *loader;
+ GHashTable *cache;
+ GHashTable *failed;
+};
+
+struct _SysprofDebuginfodSymbolizerClass
+{
+ SysprofSymbolizerClass parent_class;
+};
+
+G_DEFINE_FINAL_TYPE (SysprofDebuginfodSymbolizer, sysprof_debuginfod_symbolizer, SYSPROF_TYPE_SYMBOLIZER)
+
+static SysprofSymbol *
+sysprof_debuginfod_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
+ SysprofStrings *strings,
+ const SysprofProcessInfo *process_info,
+ SysprofAddressContext context,
+ SysprofAddress address)
+{
+ SysprofDebuginfodSymbolizer *self = SYSPROF_DEBUGINFOD_SYMBOLIZER (symbolizer);
+ g_autoptr(SysprofElf) elf = NULL;
+ g_autofree char *name = NULL;
+ SysprofSymbol *sym = NULL;
+ SysprofDocumentMmap *map;
+ const char *build_id;
+ const char *path;
+ guint64 relative_address;
+ guint64 begin_address;
+ guint64 end_address;
+ guint64 file_offset;
+ guint64 map_begin;
+ guint64 map_end;
+
+ if (process_info == NULL ||
+ process_info->address_layout == NULL ||
+ process_info->mount_namespace == NULL ||
+ (context != SYSPROF_ADDRESS_CONTEXT_NONE && context != SYSPROF_ADDRESS_CONTEXT_USER) ||
+ !(map = sysprof_address_layout_lookup (process_info->address_layout, address)))
+ return NULL;
+
+ map_begin = sysprof_document_mmap_get_start_address (map);
+ map_end = sysprof_document_mmap_get_end_address (map);
+
+ g_assert (address < map_end);
+ g_assert (address >= map_begin);
+
+ file_offset = sysprof_document_mmap_get_file_offset (map);
+ path = sysprof_document_mmap_get_file (map);
+
+ if (g_hash_table_contains (self->failed, path))
+ return NULL;
+
+ elf = sysprof_elf_loader_load (self->loader,
+ process_info->mount_namespace,
+ path,
+ sysprof_document_mmap_get_build_id (map),
+ sysprof_document_mmap_get_file_inode (map),
+ NULL);
+ if (elf == NULL)
+ return NULL;
+
+ if (!(build_id = sysprof_elf_get_build_id (elf)))
+ return NULL;
+
+ if (!g_hash_table_contains (self->cache, elf))
+ {
+ g_autoptr(SysprofDebuginfodTask) task = sysprof_debuginfod_task_new ();
+ g_autoptr(SysprofDocumentLoader) loader = g_weak_ref_get (&self->loader_wr);
+ g_autoptr(SysprofDocumentTaskScope) scope = _sysprof_document_task_register (SYSPROF_DOCUMENT_TASK (task), loader);
+ g_autoptr(SysprofElf) debuginfo_elf = NULL;
+
+ if (!(debuginfo_elf = sysprof_debuginfod_task_find_debuginfo (task, self->client, path, build_id, NULL)))
+ {
+ g_hash_table_insert (self->failed, g_strdup (path), NULL);
+ return NULL;
+ }
+
+ sysprof_elf_set_debug_link_elf (elf, debuginfo_elf);
+
+ g_hash_table_insert (self->cache, g_object_ref (elf), NULL);
+ }
+
+ relative_address = address;
+ relative_address -= map_begin;
+ relative_address += file_offset;
+
+ name = sysprof_elf_get_symbol_at_address (elf,
+ relative_address,
+ &begin_address,
+ &end_address);
+ if (!name)
+ return NULL;
+
+ begin_address = CLAMP (begin_address, file_offset, file_offset + (map_end - map_begin));
+ end_address = CLAMP (end_address, file_offset, file_offset + (map_end - map_begin));
+ if (end_address == begin_address)
+ end_address++;
+
+ sym = _sysprof_symbol_new (sysprof_strings_get (strings, name),
+ sysprof_strings_get (strings, path),
+ sysprof_strings_get (strings, sysprof_elf_get_nick (elf)),
+ map_begin + (begin_address - file_offset),
+ map_begin + (end_address - file_offset),
+ SYSPROF_SYMBOL_KIND_USER);
+
+ return sym;
+}
+
+static void
+sysprof_debuginfod_symbolizer_setup (SysprofSymbolizer *symbolizer,
+ SysprofDocumentLoader *loader)
+{
+ SysprofDebuginfodSymbolizer *self = SYSPROF_DEBUGINFOD_SYMBOLIZER (symbolizer);
+
+ g_weak_ref_set (&self->loader_wr, loader);
+}
+
+static void
+sysprof_debuginfod_symbolizer_dispose (GObject *object)
+{
+ SysprofDebuginfodSymbolizer *self = SYSPROF_DEBUGINFOD_SYMBOLIZER (object);
+
+ g_hash_table_remove_all (self->cache);
+
+ g_weak_ref_set (&self->loader_wr, NULL);
+
+ G_OBJECT_CLASS (sysprof_debuginfod_symbolizer_parent_class)->dispose (object);
+}
+
+static void
+sysprof_debuginfod_symbolizer_finalize (GObject *object)
+{
+ SysprofDebuginfodSymbolizer *self = SYSPROF_DEBUGINFOD_SYMBOLIZER (object);
+
+ g_clear_object (&self->loader);
+
+ g_clear_pointer (&self->cache, g_hash_table_unref);
+ g_clear_pointer (&self->failed, g_hash_table_unref);
+ g_clear_pointer (&self->client, debuginfod_end);
+
+ g_weak_ref_clear (&self->loader_wr);
+
+ G_OBJECT_CLASS (sysprof_debuginfod_symbolizer_parent_class)->finalize (object);
+}
+
+static void
+sysprof_debuginfod_symbolizer_class_init (SysprofDebuginfodSymbolizerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SysprofSymbolizerClass *symbolizer_class = SYSPROF_SYMBOLIZER_CLASS (klass);
+
+ object_class->dispose = sysprof_debuginfod_symbolizer_dispose;
+ object_class->finalize = sysprof_debuginfod_symbolizer_finalize;
+
+ symbolizer_class->setup = sysprof_debuginfod_symbolizer_setup;
+ symbolizer_class->symbolize = sysprof_debuginfod_symbolizer_symbolize;
+}
+
+static void
+sysprof_debuginfod_symbolizer_init (SysprofDebuginfodSymbolizer *self)
+{
+ g_weak_ref_init (&self->loader_wr, NULL);
+}
+
+SysprofSymbolizer *
+sysprof_debuginfod_symbolizer_new (GError **error)
+{
+ g_autoptr(SysprofDebuginfodSymbolizer) self = NULL;
+
+ self = g_object_new (SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER, NULL);
+ self->client = debuginfod_begin ();
+
+ if (self->client == NULL)
+ {
+ int errsv = errno;
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ g_strerror (errsv));
+ return NULL;
+ }
+
+ self->loader = sysprof_elf_loader_new ();
+ self->cache = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
+ self->failed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ return SYSPROF_SYMBOLIZER (g_steal_pointer (&self));
+}
diff --git a/src/libsysprof/sysprof-debuginfod-symbolizer.h b/src/libsysprof/sysprof-debuginfod-symbolizer.h
new file mode 100644
index 00000000..3a01e566
--- /dev/null
+++ b/src/libsysprof/sysprof-debuginfod-symbolizer.h
@@ -0,0 +1,42 @@
+/* sysprof-debuginfod-symbolizer.h
+ *
+ * Copyright 2024 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 "sysprof-symbolizer.h"
+
+G_BEGIN_DECLS
+
+#define SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER (sysprof_debuginfod_symbolizer_get_type())
+#define SYSPROF_IS_DEBUGINFOD_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER)
+#define SYSPROF_DEBUGINFOD_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER, SysprofDebuginfodSymbolizer)
+#define SYSPROF_DEBUGINFOD_SYMBOLIZER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER, SysprofDebuginfodSymbolizerClass)
+
+typedef struct _SysprofDebuginfodSymbolizer SysprofDebuginfodSymbolizer;
+typedef struct _SysprofDebuginfodSymbolizerClass SysprofDebuginfodSymbolizerClass;
+
+SYSPROF_AVAILABLE_IN_47
+GType sysprof_debuginfod_symbolizer_get_type (void) G_GNUC_CONST;
+SYSPROF_AVAILABLE_IN_47
+SysprofSymbolizer *sysprof_debuginfod_symbolizer_new (GError **error);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDebuginfodSymbolizer, g_object_unref)
+
+G_END_DECLS
diff --git a/src/libsysprof/sysprof-debuginfod-task-private.h b/src/libsysprof/sysprof-debuginfod-task-private.h
new file mode 100644
index 00000000..33e595ec
--- /dev/null
+++ b/src/libsysprof/sysprof-debuginfod-task-private.h
@@ -0,0 +1,42 @@
+/*
+ * sysprof-debuginfod-task-private.h
+ *
+ * Copyright 2024 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 <elfutils/debuginfod.h>
+
+#include "sysprof-document-task-private.h"
+#include "sysprof-elf-private.h"
+
+G_BEGIN_DECLS
+
+#define SYSPROF_TYPE_DEBUGINFOD_TASK (sysprof_debuginfod_task_get_type())
+
+G_DECLARE_FINAL_TYPE (SysprofDebuginfodTask, sysprof_debuginfod_task, SYSPROF, DEBUGINFOD_TASK, SysprofDocumentTask)
+
+SysprofDebuginfodTask *sysprof_debuginfod_task_new (void);
+SysprofElf *sysprof_debuginfod_task_find_debuginfo (SysprofDebuginfodTask *self,
+ debuginfod_client *client,
+ const char *path,
+ const char *build_id_string,
+ GError **error);
+
+G_END_DECLS
diff --git a/src/libsysprof/sysprof-debuginfod-task.c b/src/libsysprof/sysprof-debuginfod-task.c
new file mode 100644
index 00000000..0f996d09
--- /dev/null
+++ b/src/libsysprof/sysprof-debuginfod-task.c
@@ -0,0 +1,131 @@
+/*
+ * sysprof-debuginfod-task.c
+ *
+ * Copyright 2024 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 <glib/gstdio.h>
+#include <glib/gi18n.h>
+
+#include <gio/gio.h>
+
+#include "sysprof-debuginfod-task-private.h"
+
+struct _SysprofDebuginfodTask
+{
+ SysprofDocumentTask parent_instance;
+};
+
+G_DEFINE_FINAL_TYPE (SysprofDebuginfodTask, sysprof_debuginfod_task, SYSPROF_TYPE_DOCUMENT_TASK)
+
+static void
+sysprof_debuginfod_task_class_init (SysprofDebuginfodTaskClass *klass)
+{
+}
+
+static void
+sysprof_debuginfod_task_init (SysprofDebuginfodTask *self)
+{
+}
+
+SysprofDebuginfodTask *
+sysprof_debuginfod_task_new (void)
+{
+ return g_object_new (SYSPROF_TYPE_DEBUGINFOD_TASK, NULL);
+}
+
+static int
+sysprof_debuginfod_task_progress_cb (debuginfod_client *client,
+ long a,
+ long b)
+{
+ SysprofDocumentTask *task = debuginfod_get_user_data (client);
+ double progress;
+
+ g_assert (client != NULL);
+ g_assert (SYSPROF_IS_DEBUGINFOD_TASK (task));
+
+ if (b > 0)
+ progress = (double)a / (double)b;
+ else
+ progress = 0;
+
+ _sysprof_document_task_set_progress (task, progress);
+
+ if (sysprof_document_task_is_cancelled (task))
+ return -1;
+
+ return 0;
+}
+
+SysprofElf *
+sysprof_debuginfod_task_find_debuginfo (SysprofDebuginfodTask *self,
+ debuginfod_client *client,
+ const char *path,
+ const char *build_id_string,
+ GError **error)
+{
+ g_autoptr(GMappedFile) mapped_file = NULL;
+ g_autoptr(SysprofElf) debuginfo_elf = NULL;
+ g_autofd int fd = -1;
+ char *debuginfo_path = NULL;
+
+ g_return_val_if_fail (SYSPROF_IS_DEBUGINFOD_TASK (self), NULL);
+ g_return_val_if_fail (client != NULL, NULL);
+ g_return_val_if_fail (build_id_string != NULL, NULL);
+
+ debuginfod_set_user_data (client, self);
+ debuginfod_set_progressfn (client, sysprof_debuginfod_task_progress_cb);
+
+ _sysprof_document_task_set_title (SYSPROF_DOCUMENT_TASK (self), _("Downloading Symbols…"));
+ _sysprof_document_task_take_message (SYSPROF_DOCUMENT_TASK (self), g_strdup (path));
+
+ fd = debuginfod_find_debuginfo (client,
+ (const unsigned char *)build_id_string, 0,
+ &debuginfo_path);
+
+ if (fd < 0)
+ {
+ if (error != NULL)
+ {
+ int errsv = errno;
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ g_strerror (errsv));
+ }
+
+ goto failure;
+ }
+
+ if (!(mapped_file = g_mapped_file_new_from_fd (fd, FALSE, error)))
+ goto failure;
+
+ if (!(debuginfo_elf = sysprof_elf_new (debuginfo_path, g_steal_pointer (&mapped_file), 0, error)))
+ goto failure;
+
+failure:
+ free (debuginfo_path);
+
+ debuginfod_set_user_data (client, NULL);
+ debuginfod_set_progressfn (client, NULL);
+
+ return g_steal_pointer (&debuginfo_elf);
+}
diff --git a/src/libsysprof/sysprof-document-loader.c b/src/libsysprof/sysprof-document-loader.c
index 3cd408c4..00b525df 100644
--- a/src/libsysprof/sysprof-document-loader.c
+++ b/src/libsysprof/sysprof-document-loader.c
@@ -196,7 +196,6 @@ static void
set_default_symbolizer (SysprofDocumentLoader *self)
{
g_autoptr(SysprofMultiSymbolizer) multi = NULL;
- g_autoptr(SysprofSymbolizer) debuginfod = NULL;
g_autoptr(GError) error = NULL;
g_assert (SYSPROF_IS_DOCUMENT_LOADER (self));
@@ -209,10 +208,16 @@ set_default_symbolizer (SysprofDocumentLoader *self)
sysprof_multi_symbolizer_take (multi, sysprof_elf_symbolizer_new ());
sysprof_multi_symbolizer_take (multi, sysprof_jitmap_symbolizer_new ());
- if (!(debuginfod = sysprof_debuginfod_symbolizer_new (&error)))
- g_warning ("Failed to create debuginfod symbolizer: %s", error->message);
- else
- sysprof_multi_symbolizer_take (multi, g_steal_pointer (&debuginfod));
+#if HAVE_DEBUGINFOD
+ {
+ g_autoptr(SysprofSymbolizer) debuginfod = NULL;
+
+ if (!(debuginfod = sysprof_debuginfod_symbolizer_new (&error)))
+ g_warning ("Failed to create debuginfod symbolizer: %s", error->message);
+ else
+ sysprof_multi_symbolizer_take (multi, g_steal_pointer (&debuginfod));
+ }
+#endif
self->symbolizer = SYSPROF_SYMBOLIZER (g_steal_pointer (&multi));
}
--
2.45.2

View File

@ -0,0 +1,26 @@
From 9895b74a43dcbb41704572d2304d03d4d24397f2 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Fri, 11 Oct 2024 11:08:52 -0700
Subject: [PATCH 09/31] libsysprof: ensure access to process info
---
src/libsysprof/sysprof-document-symbols.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/libsysprof/sysprof-document-symbols.c b/src/libsysprof/sysprof-document-symbols.c
index 828c7fb6..e5584a69 100644
--- a/src/libsysprof/sysprof-document-symbols.c
+++ b/src/libsysprof/sysprof-document-symbols.c
@@ -112,6 +112,9 @@ do_symbolize (SysprofSymbolizer *symbolizer,
* and where (relative to that file) the IP was.
*/
+ if (process_info == NULL || process_info->address_layout == NULL)
+ return NULL;
+
if (!(map = sysprof_address_layout_lookup (process_info->address_layout, address)))
return NULL;
--
2.45.2

View File

@ -0,0 +1,25 @@
From 2c89e348dd469913cf80a1dc4f003aaf5ae7c2ba Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Fri, 11 Oct 2024 11:26:13 -0700
Subject: [PATCH 10/31] libsysprof: fix building with -Ddebuginfod=auto
---
src/libsysprof/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index b4e58078..ce6e37f2 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -153,7 +153,7 @@ libsysprof_private_sources = [
'timsort/gtktimsort.c',
]
-if debuginfod_dep.found() and get_option('debuginfod').enabled()
+if debuginfod_dep.found()
libsysprof_private_sources += [
'sysprof-debuginfod-symbolizer.c',
'sysprof-debuginfod-task.c'
--
2.45.2

View File

@ -0,0 +1,158 @@
From c81b5ae5e690eba77498c3a79db168467641d286 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Fri, 11 Oct 2024 11:45:41 -0700
Subject: [PATCH 11/31] libsysprof: return NULL instance unless debuginfod
works
If we are configured with support for debuginfod and it fails to initialize
or we are not configured to use debuginfod, always ensure g_object_new()
will return a NULL instance back.
This helps prevent against misconfigured instances so we do not need to
do so many checks in vfuncs as well as allowing us to have the GType be
available always even when not built with debuginfod.
---
.../sysprof-debuginfod-symbolizer.c | 66 +++++++++++++++----
1 file changed, 53 insertions(+), 13 deletions(-)
diff --git a/src/libsysprof/sysprof-debuginfod-symbolizer.c b/src/libsysprof/sysprof-debuginfod-symbolizer.c
index 8dd60d19..bcad9a5c 100644
--- a/src/libsysprof/sysprof-debuginfod-symbolizer.c
+++ b/src/libsysprof/sysprof-debuginfod-symbolizer.c
@@ -20,18 +20,22 @@
#include "config.h"
-#include <elfutils/debuginfod.h>
#include <errno.h>
-#include <stdatomic.h>
#include <glib/gstdio.h>
#include "sysprof-symbolizer-private.h"
#include "sysprof-debuginfod-symbolizer.h"
-#include "sysprof-debuginfod-task-private.h"
#include "sysprof-elf-loader-private.h"
#include "sysprof-symbol-private.h"
+#if HAVE_DEBUGINFOD
+# include <elfutils/debuginfod.h>
+# include "sysprof-debuginfod-task-private.h"
+#else
+typedef struct _debuginfod_client debuginfod_client;
+#endif
+
struct _SysprofDebuginfodSymbolizer
{
SysprofSymbolizer parent_instance;
@@ -58,6 +62,7 @@ sysprof_debuginfod_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
SysprofAddressContext context,
SysprofAddress address)
{
+#if HAVE_DEBUGINFOD
SysprofDebuginfodSymbolizer *self = SYSPROF_DEBUGINFOD_SYMBOLIZER (symbolizer);
g_autoptr(SysprofElf) elf = NULL;
g_autofree char *name = NULL;
@@ -145,6 +150,9 @@ sysprof_debuginfod_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
SYSPROF_SYMBOL_KIND_USER);
return sym;
+#else
+ return NULL;
+#endif
}
static void
@@ -177,19 +185,54 @@ sysprof_debuginfod_symbolizer_finalize (GObject *object)
g_clear_pointer (&self->cache, g_hash_table_unref);
g_clear_pointer (&self->failed, g_hash_table_unref);
+
+#if HAVE_DEBUGINFOD
g_clear_pointer (&self->client, debuginfod_end);
+#endif
g_weak_ref_clear (&self->loader_wr);
G_OBJECT_CLASS (sysprof_debuginfod_symbolizer_parent_class)->finalize (object);
}
+static GObject *
+sysprof_debuginfod_symbolizer_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_properties)
+{
+#if HAVE_DEBUGINFOD
+ debuginfod_client *client;
+ GObject *object;
+
+ g_assert (type == SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER);
+
+ /* Don't even allow creating a SysprofDebuginfodSymbolizer instance unless we
+ * can create a new debuginfod_client. This ensures that even if an application
+ * does `g_object_new(SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER, NULL)` they will get
+ * `NULL` back instead of a misconfigured instance.
+ */
+ if (!(client = debuginfod_begin ()))
+ return NULL;
+
+ object = G_OBJECT_CLASS (sysprof_debuginfod_symbolizer_parent_class)
+ ->constructor (type, n_construct_params, construct_properties);
+
+ SYSPROF_DEBUGINFOD_SYMBOLIZER (object)->client = client;
+
+ return object;
+#else
+ errno = ENOTSUP;
+ return NULL;
+#endif
+}
+
static void
sysprof_debuginfod_symbolizer_class_init (SysprofDebuginfodSymbolizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
SysprofSymbolizerClass *symbolizer_class = SYSPROF_SYMBOLIZER_CLASS (klass);
+ object_class->constructor = sysprof_debuginfod_symbolizer_constructor;
object_class->dispose = sysprof_debuginfod_symbolizer_dispose;
object_class->finalize = sysprof_debuginfod_symbolizer_finalize;
@@ -201,17 +244,18 @@ static void
sysprof_debuginfod_symbolizer_init (SysprofDebuginfodSymbolizer *self)
{
g_weak_ref_init (&self->loader_wr, NULL);
+
+ self->loader = sysprof_elf_loader_new ();
+ self->cache = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
+ self->failed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
SysprofSymbolizer *
sysprof_debuginfod_symbolizer_new (GError **error)
{
- g_autoptr(SysprofDebuginfodSymbolizer) self = NULL;
+ SysprofSymbolizer *self;
- self = g_object_new (SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER, NULL);
- self->client = debuginfod_begin ();
-
- if (self->client == NULL)
+ if (!(self = g_object_new (SYSPROF_TYPE_DEBUGINFOD_SYMBOLIZER, NULL)))
{
int errsv = errno;
g_set_error_literal (error,
@@ -221,9 +265,5 @@ sysprof_debuginfod_symbolizer_new (GError **error)
return NULL;
}
- self->loader = sysprof_elf_loader_new ();
- self->cache = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
- self->failed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
- return SYSPROF_SYMBOLIZER (g_steal_pointer (&self));
+ return self;
}
--
2.45.2

View File

@ -0,0 +1,56 @@
From e15c1147f1543af5900f1caa8c1adf41a52a8a68 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Fri, 11 Oct 2024 11:46:26 -0700
Subject: [PATCH 12/31] build: always build debuginfod symbolizer
Even if it is disabled, we want the GType enabled and part of our ABI. We
will return NULL if one is created and debuginfod is not supported or if
we failed to create a client.
---
src/libsysprof/meson.build | 3 ++-
src/libsysprof/sysprof.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index ce6e37f2..549042de 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -10,6 +10,7 @@ libsysprof_public_sources = [
'sysprof-cpu-info.c',
'sysprof-cpu-usage.c',
'sysprof-dbus-monitor.c',
+ 'sysprof-debuginfod-symbolizer.c',
'sysprof-diagnostic.c',
'sysprof-disk-usage.c',
'sysprof-document-allocation.c',
@@ -75,6 +76,7 @@ libsysprof_public_headers = [
'sysprof-cpu-info.h',
'sysprof-cpu-usage.h',
'sysprof-dbus-monitor.h',
+ 'sysprof-debuginfod-symbolizer.h',
'sysprof-diagnostic.h',
'sysprof-disk-usage.h',
'sysprof-document-allocation.h',
@@ -155,7 +157,6 @@ libsysprof_private_sources = [
if debuginfod_dep.found()
libsysprof_private_sources += [
- 'sysprof-debuginfod-symbolizer.c',
'sysprof-debuginfod-task.c'
]
endif
diff --git a/src/libsysprof/sysprof.h b/src/libsysprof/sysprof.h
index c2176619..d30f9fd4 100644
--- a/src/libsysprof/sysprof.h
+++ b/src/libsysprof/sysprof.h
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
# include "sysprof-cpu-info.h"
# include "sysprof-cpu-usage.h"
# include "sysprof-dbus-monitor.h"
+# include "sysprof-debuginfod-symbolizer.h"
# include "sysprof-diagnostic.h"
# include "sysprof-disk-usage.h"
# include "sysprof-document-allocation.h"
--
2.45.2

View File

@ -0,0 +1,49 @@
From 2f9eb12a3348ae41d51bbeb56fd293c5204b7851 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 23 Oct 2024 11:54:33 -0700
Subject: [PATCH 13/31] libsysprof: remove unnecessary address calculation
We are only fallback symbols here, which is 1 address-wide.
---
src/libsysprof/sysprof-document-symbols.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/src/libsysprof/sysprof-document-symbols.c b/src/libsysprof/sysprof-document-symbols.c
index e5584a69..642f702b 100644
--- a/src/libsysprof/sysprof-document-symbols.c
+++ b/src/libsysprof/sysprof-document-symbols.c
@@ -100,8 +100,6 @@ do_symbolize (SysprofSymbolizer *symbolizer,
guint64 map_begin;
guint64 map_end;
guint64 relative_address;
- guint64 begin_address;
- guint64 end_address;
guint64 file_offset;
if ((ret = _sysprof_symbolizer_symbolize (symbolizer, strings, process_info, last_context, address)))
@@ -132,21 +130,14 @@ do_symbolize (SysprofSymbolizer *symbolizer,
path = sysprof_document_mmap_get_file (map);
- begin_address = CLAMP (begin_address, file_offset, file_offset + (map_end - map_begin));
- end_address = CLAMP (end_address, file_offset, file_offset + (map_end - map_begin));
- if (end_address == begin_address)
- end_address++;
-
name = g_strdup_printf ("In File %s+0x%"G_GINT64_MODIFIER"x",
sysprof_document_mmap_get_file (map),
relative_address);
- begin_address = address;
- end_address = address + 1;
ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
sysprof_strings_get (strings, path),
sysprof_strings_get (strings, nick),
- begin_address, end_address,
+ address, address + 1,
SYSPROF_SYMBOL_KIND_USER);
ret->is_fallback = TRUE;
--
2.45.2

View File

@ -0,0 +1,251 @@
From 917b05544e46282ee3d77dcd4ab050df5f80a1d3 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Fri, 25 Oct 2024 10:49:15 -0700
Subject: [PATCH 14/31] libsysprof: add muxer GSource
This allows copying events from a capture stream transparently into the
destination. No processing of the stream is performed, but that may change
in the future to accomidate JIT/Counter translations.
Internal only as support for upcoming live unwinding via external process.
---
src/libsysprof/meson.build | 1 +
src/libsysprof/sysprof-muxer-source.c | 173 ++++++++++++++++++++++++++
src/libsysprof/sysprof-muxer-source.h | 33 +++++
3 files changed, 207 insertions(+)
create mode 100644 src/libsysprof/sysprof-muxer-source.c
create mode 100644 src/libsysprof/sysprof-muxer-source.h
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index 549042de..f3fa0850 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -147,6 +147,7 @@ libsysprof_private_sources = [
'sysprof-mount-device.c',
'sysprof-mount-namespace.c',
'sysprof-mount.c',
+ 'sysprof-muxer-source.c',
'sysprof-perf-event-stream.c',
'sysprof-podman.c',
'sysprof-process-info.c',
diff --git a/src/libsysprof/sysprof-muxer-source.c b/src/libsysprof/sysprof-muxer-source.c
new file mode 100644
index 00000000..c037a38f
--- /dev/null
+++ b/src/libsysprof/sysprof-muxer-source.c
@@ -0,0 +1,173 @@
+/*
+ * sysprof-muxer-source.c
+ *
+ * Copyright 2024 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 <glib/gstdio.h>
+#include <glib-unix.h>
+
+#include "sysprof-muxer-source.h"
+
+#define DEFAULT_BUFFER_SIZE (4096*16)
+
+typedef struct _SysprofMuxerSource
+{
+ GSource gsource;
+ int capture_fd;
+ SysprofCaptureWriter *writer;
+ struct {
+ guint8 *allocation;
+ guint8 *begin;
+ guint8 *end;
+ guint8 *capacity;
+ gsize to_skip;
+ } buffer;
+} SysprofMuxerSource;
+
+static gboolean
+sysprof_muxer_source_size (SysprofMuxerSource *source)
+{
+ return source->buffer.end - source->buffer.begin;
+}
+
+static gboolean
+sysprof_muxer_source_dispatch (GSource *gsource,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ SysprofMuxerSource *source = (SysprofMuxerSource *)gsource;
+ gssize n_read;
+
+ g_assert (source != NULL);
+ g_assert (source->writer != NULL);
+
+ /* Try to read the next chunk */
+ n_read = read (source->capture_fd, source->buffer.end, source->buffer.capacity - source->buffer.end);
+
+ if (n_read > 0)
+ {
+ const SysprofCaptureFrame *frame;
+
+ /* Advance tail to what was filled */
+ source->buffer.end += n_read;
+
+ /* Get to next alignment */
+ if (source->buffer.to_skip)
+ {
+ gsize amount = MIN (source->buffer.to_skip, source->buffer.end - source->buffer.begin);
+ source->buffer.begin += amount;
+ source->buffer.to_skip -= amount;
+ }
+
+ /* If there is enough to read the frame header, try to read and dispatch
+ * it in raw form. We assume we're the same endianness here because this
+ * is coming from the same host (live-unwinder currently).
+ */
+ while (sysprof_muxer_source_size (source) >= sizeof *frame)
+ {
+ frame = (const SysprofCaptureFrame *)source->buffer.begin;
+
+ if (frame->len <= sysprof_muxer_source_size (source))
+ {
+ source->buffer.begin += frame->len;
+
+ if (frame->len % sizeof (guint64) != 0)
+ source->buffer.to_skip = sizeof (guint64) - (frame->len % sizeof (guint64));
+
+ /* TODO: Technically for counters/JIT map we need to translate them. */
+
+ _sysprof_capture_writer_add_raw (source->writer, frame);
+ }
+
+ if (source->buffer.to_skip > 0 &&
+ source->buffer.to_skip <= sysprof_muxer_source_size (source))
+ {
+ source->buffer.begin += source->buffer.to_skip;
+ source->buffer.to_skip = 0;
+ continue;
+ }
+
+ break;
+ }
+
+ /* Move anything left to the head of the buffer so we can
+ * fill in the entire next frame of data.
+ */
+ if (source->buffer.begin < source->buffer.end)
+ {
+ /* TODO: Should we adjust for alignment here? */
+
+ memmove (source->buffer.allocation,
+ source->buffer.begin,
+ source->buffer.end - source->buffer.begin);
+ source->buffer.end = source->buffer.allocation + (source->buffer.end - source->buffer.begin);
+ source->buffer.begin = source->buffer.allocation;
+ }
+ else
+ {
+ source->buffer.end = source->buffer.allocation;
+ source->buffer.begin = source->buffer.allocation;
+ }
+ }
+
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+sysprof_muxer_source_finalize (GSource *gsource)
+{
+ SysprofMuxerSource *source = (SysprofMuxerSource *)gsource;
+
+ g_clear_fd (&source->capture_fd, NULL);
+ g_clear_pointer (&source->writer, sysprof_capture_writer_unref);
+ g_clear_pointer (&source->buffer.begin, g_free);
+}
+
+static const GSourceFuncs source_funcs = {
+ .dispatch = sysprof_muxer_source_dispatch,
+ .finalize = sysprof_muxer_source_finalize,
+};
+
+GSource *
+sysprof_muxer_source_new (int capture_fd,
+ SysprofCaptureWriter *writer)
+{
+ SysprofMuxerSource *source;
+
+ g_return_val_if_fail (capture_fd > -1, NULL);
+ g_return_val_if_fail (writer != NULL, NULL);
+
+ source = (SysprofMuxerSource *)g_source_new ((GSourceFuncs *)&source_funcs, sizeof (SysprofMuxerSource));
+ source->capture_fd = capture_fd;
+ source->writer = sysprof_capture_writer_ref (writer);
+ source->buffer.allocation = g_malloc (DEFAULT_BUFFER_SIZE);
+ source->buffer.begin = source->buffer.allocation;
+ source->buffer.end = source->buffer.allocation;
+ source->buffer.capacity = source->buffer.allocation + DEFAULT_BUFFER_SIZE;
+ source->buffer.to_skip = sizeof (SysprofCaptureFileHeader);
+
+ g_unix_set_fd_nonblocking (capture_fd, TRUE, NULL);
+
+ g_source_add_unix_fd ((GSource *)source, capture_fd, G_IO_IN);
+
+ return (GSource *)source;
+}
diff --git a/src/libsysprof/sysprof-muxer-source.h b/src/libsysprof/sysprof-muxer-source.h
new file mode 100644
index 00000000..9b9a94e1
--- /dev/null
+++ b/src/libsysprof/sysprof-muxer-source.h
@@ -0,0 +1,33 @@
+/*
+ * sysprof-muxer-source.h
+ *
+ * Copyright 2024 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.h>
+
+#include <sysprof-capture.h>
+
+G_BEGIN_DECLS
+
+GSource *sysprof_muxer_source_new (int capture_fd,
+ SysprofCaptureWriter *writer);
+
+G_END_DECLS
--
2.45.2

View File

@ -0,0 +1,138 @@
From 4583026b751c3d00294ecec6ed1be11dcaf17623 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Sun, 3 Nov 2024 10:39:23 -0800
Subject: [PATCH 15/31] libsysprof: add support for stack/regs options in attr
This requires a coordinating sysprofd that knows how to handle reading the
new attributes. Setting these fields will allow snapshotting the contents
of the stack and registers to do offline unwinding.
Also make the conversion to GVariant available outside the module so that
we can consume it for live unwinding.
---
.../sysprof-perf-event-stream-private.h | 25 ++++++++++---------
src/libsysprof/sysprof-perf-event-stream.c | 10 +++++---
src/sysprofd/helpers.c | 16 ++++++++++++
3 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/src/libsysprof/sysprof-perf-event-stream-private.h b/src/libsysprof/sysprof-perf-event-stream-private.h
index 4ac0fd1e..7e3d9deb 100644
--- a/src/libsysprof/sysprof-perf-event-stream-private.h
+++ b/src/libsysprof/sysprof-perf-event-stream-private.h
@@ -165,17 +165,18 @@ typedef void (*SysprofPerfEventCallback) (const SysprofPerfEvent *event,
G_DECLARE_FINAL_TYPE (SysprofPerfEventStream, sysprof_perf_event_stream, SYSPROF, PERF_EVENT_STREAM, GObject)
-DexFuture *sysprof_perf_event_stream_new (GDBusConnection *connection,
- struct perf_event_attr *attr,
- int cpu,
- int group_fd,
- guint64 flags,
- SysprofPerfEventCallback callback,
- gpointer callback_data,
- GDestroyNotify callback_data_destroy);
-gboolean sysprof_perf_event_stream_enable (SysprofPerfEventStream *self,
- GError **error);
-gboolean sysprof_perf_event_stream_disable (SysprofPerfEventStream *self,
- GError **error);
+DexFuture *sysprof_perf_event_stream_new (GDBusConnection *connection,
+ struct perf_event_attr *attr,
+ int cpu,
+ int group_fd,
+ guint64 flags,
+ SysprofPerfEventCallback callback,
+ gpointer callback_data,
+ GDestroyNotify callback_data_destroy);
+gboolean sysprof_perf_event_stream_enable (SysprofPerfEventStream *self,
+ GError **error);
+gboolean sysprof_perf_event_stream_disable (SysprofPerfEventStream *self,
+ GError **error);
+GVariant *_sysprof_perf_event_attr_to_variant (const struct perf_event_attr *attr);
G_END_DECLS
diff --git a/src/libsysprof/sysprof-perf-event-stream.c b/src/libsysprof/sysprof-perf-event-stream.c
index a7bf8d88..c40182ad 100644
--- a/src/libsysprof/sysprof-perf-event-stream.c
+++ b/src/libsysprof/sysprof-perf-event-stream.c
@@ -109,8 +109,8 @@ G_DEFINE_FINAL_TYPE (SysprofPerfEventStream, sysprof_perf_event_stream, G_TYPE_O
static GParamSpec *properties [N_PROPS];
-static GVariant *
-build_options_dict (const struct perf_event_attr *attr)
+GVariant *
+_sysprof_perf_event_attr_to_variant (const struct perf_event_attr *attr)
{
return g_variant_take_ref (
g_variant_new_parsed ("["
@@ -130,6 +130,8 @@ build_options_dict (const struct perf_event_attr *attr)
"{'sample_period', <%t>},"
"{'sample_type', <%t>},"
"{'task', <%b>},"
+ "{'sample_stack_user', <%u>},"
+ "{'sample_regs_user', <%t>},"
"{'type', <%u>}"
"]",
(gboolean)!!attr->comm,
@@ -148,6 +150,8 @@ build_options_dict (const struct perf_event_attr *attr)
(guint64)attr->sample_period,
(guint64)attr->sample_type,
(gboolean)!!attr->task,
+ (guint32)attr->sample_stack_user,
+ (guint64)attr->sample_regs_user,
(guint32)attr->type));
}
@@ -513,7 +517,7 @@ sysprof_perf_event_stream_new (GDBusConnection *connection,
group_fd_handle = g_unix_fd_list_append (fd_list, group_fd, NULL);
}
- options = build_options_dict (attr);
+ options = _sysprof_perf_event_attr_to_variant (attr);
g_dbus_connection_call_with_unix_fd_list (connection,
"org.gnome.Sysprof3",
diff --git a/src/sysprofd/helpers.c b/src/sysprofd/helpers.c
index 2aebc417..7e5df34a 100644
--- a/src/sysprofd/helpers.c
+++ b/src/sysprofd/helpers.c
@@ -127,6 +127,8 @@ helpers_perf_event_open (GVariant *options,
guint64 sample_period = 0;
guint64 sample_type = 0;
guint64 config = 0;
+ guint64 sample_regs_user = 0;
+ guint sample_stack_user = 0;
int clockid = CLOCK_MONOTONIC;
int comm = 0;
int mmap_ = 0;
@@ -236,6 +238,18 @@ helpers_perf_event_open (GVariant *options,
goto bad_arg;
use_clockid = g_variant_get_boolean (value);
}
+ else if (strcmp (key, "sample_stack_user") == 0)
+ {
+ if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))
+ goto bad_arg;
+ sample_stack_user = g_variant_get_uint32 (value);
+ }
+ else if (strcmp (key, "sample_regs_user") == 0)
+ {
+ if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64))
+ goto bad_arg;
+ sample_regs_user = g_variant_get_uint64 (value);
+ }
continue;
@@ -257,6 +271,8 @@ helpers_perf_event_open (GVariant *options,
attr.task = !!task;
attr.type = type;
attr.wakeup_events = wakeup_events;
+ attr.sample_regs_user = sample_regs_user;
+ attr.sample_stack_user = sample_stack_user;
#ifdef HAVE_PERF_CLOCKID
if (!use_clockid || clockid < 0)
--
2.45.2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,694 @@
From a58aa3b33173e5fab8ec81b6b2961e2113ea716b Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Sun, 3 Nov 2024 10:53:29 -0800
Subject: [PATCH 17/31] libsysprof: add SysprofUserSampler for live unwinding
This instrument triggers the live unwinder in sysprofd to capture a
pre-configured amount of stack contents and CPU registers. You can use
this instead of SysprofSampler in cases where you do not have frame-
pointers but want a useful trace.
It does have a moderate amount of CPU overhead compared to just relying
on frame-pointers so keep that in mind. Generally useful on platforms
that do not have frame pointers such as CentOS.
---
src/libsysprof/meson.build | 7 +
src/libsysprof/sysprof-user-sampler.c | 570 ++++++++++++++++++++++++++
src/libsysprof/sysprof-user-sampler.h | 43 ++
src/libsysprof/sysprof.h | 1 +
4 files changed, 621 insertions(+)
create mode 100644 src/libsysprof/sysprof-user-sampler.c
create mode 100644 src/libsysprof/sysprof-user-sampler.h
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index f3fa0850..e49c3a37 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -63,6 +63,7 @@ libsysprof_public_sources = [
'sysprof-time-span.c',
'sysprof-tracefd-consumer.c',
'sysprof-tracer.c',
+ 'sysprof-user-sampler.c',
]
libsysprof_public_headers = [
@@ -130,6 +131,7 @@ libsysprof_public_headers = [
'sysprof-time-span.h',
'sysprof-tracefd-consumer.h',
'sysprof-tracer.h',
+ 'sysprof-user-sampler.h',
]
libsysprof_private_sources = [
@@ -154,6 +156,11 @@ libsysprof_private_sources = [
'sysprof-strings.c',
'sysprof-symbol-cache.c',
'timsort/gtktimsort.c',
+
+ gnome.gdbus_codegen('ipc-unwinder',
+ sources: '../sysprofd/org.gnome.Sysprof3.Unwinder.xml',
+ interface_prefix: 'org.gnome.Sysprof3.',
+ namespace: 'Ipc'),
]
if debuginfod_dep.found()
diff --git a/src/libsysprof/sysprof-user-sampler.c b/src/libsysprof/sysprof-user-sampler.c
new file mode 100644
index 00000000..0e3afeae
--- /dev/null
+++ b/src/libsysprof/sysprof-user-sampler.c
@@ -0,0 +1,570 @@
+/* sysprof-user-sampler.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 <sys/ioctl.h>
+#include <sys/eventfd.h>
+
+#include <asm/perf_regs.h>
+
+#include <glib/gstdio.h>
+
+#include "sysprof-instrument-private.h"
+#include "sysprof-perf-event-stream-private.h"
+#include "sysprof-recording-private.h"
+#include "sysprof-user-sampler.h"
+#include "sysprof-muxer-source.h"
+
+#include "ipc-unwinder.h"
+
+/* The following was provided to Sysprof by Serhei Makarov as part
+ * of the eu-stacktrace prototype work.
+ */
+#ifdef _ASM_X86_PERF_REGS_H
+/* #define SYSPROF_ARCH_PREFERRED_REGS PERF_REG_EXTENDED_MASK -- error on x86_64 due to including segment regs*/
+#define REG(R) (1ULL << PERF_REG_X86_ ## R)
+#define DWARF_NEEDED_REGS (/* no FLAGS */ REG(IP) | REG(SP) | REG(AX) | REG(CX) | REG(DX) | REG(BX) | REG(SI) | REG(DI) | REG(SP) | REG(BP) | /* no segment regs */ REG(R8) | REG(R9) | REG(R10) | REG(R11) | REG(R12) | REG(R13) | REG(R14) | REG(R15))
+/* XXX register ordering is defined in linux arch/x86/include/uapi/asm/perf_regs.h;
+ see code in tools/perf/util/intel-pt.c intel_pt_add_gp_regs()
+ and note how registers are added in the same order as the perf_regs.h enum */
+#define SYSPROF_ARCH_PREFERRED_REGS DWARF_NEEDED_REGS
+/* TODO: add other architectures, imitating the linux tools/perf tree */
+#else
+# define SYSPROF_ARCH_PREFERRED_REGS PERF_REG_EXTENDED_MASK
+#endif /* _ASM_{arch}_PERF_REGS_H */
+
+#define N_WAKEUP_EVENTS 149
+
+struct _SysprofUserSampler
+{
+ SysprofInstrument parent_instance;
+ GArray *perf_fds;
+ int capture_fd;
+ int event_fd;
+ guint stack_size;
+};
+
+struct _SysprofUserSamplerClass
+{
+ SysprofInstrumentClass parent_class;
+};
+
+G_DEFINE_FINAL_TYPE (SysprofUserSampler, sysprof_user_sampler, SYSPROF_TYPE_INSTRUMENT)
+
+static void
+close_fd (gpointer data)
+{
+ int *fdp = data;
+
+ if (*fdp != -1)
+ {
+ close (*fdp);
+ *fdp = -1;
+ }
+}
+
+static void
+sysprof_user_sampler_ioctl (SysprofUserSampler *self,
+ gboolean enable)
+{
+ for (guint i = 0; i < self->perf_fds->len; i++)
+ {
+ int perf_fd = g_array_index (self->perf_fds, int, i);
+
+ if (0 != ioctl (perf_fd, enable ? PERF_EVENT_IOC_ENABLE : PERF_EVENT_IOC_DISABLE))
+ {
+ int errsv = errno;
+ g_warning ("Failed to toggle perf_fd: %s", g_strerror (errsv));
+ }
+ }
+}
+
+static char **
+sysprof_user_sampler_list_required_policy (SysprofInstrument *instrument)
+{
+ static const char *policy[] = {"org.gnome.sysprof3.profile", NULL};
+
+ return g_strdupv ((char **)policy);
+}
+
+typedef struct _Prepare
+{
+ SysprofRecording *recording;
+ SysprofUserSampler *sampler;
+ guint stack_size;
+} Prepare;
+
+static void
+prepare_free (Prepare *prepare)
+{
+ g_clear_object (&prepare->recording);
+ g_clear_object (&prepare->sampler);
+ g_free (prepare);
+}
+
+static void
+_perf_event_open_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusConnection *connection = (GDBusConnection *)object;
+ g_autoptr(DexPromise) promise = user_data;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ g_autoptr(GVariant) ret = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (G_IS_DBUS_CONNECTION (connection));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (DEX_IS_PROMISE (promise));
+
+ if ((ret = g_dbus_connection_call_with_unix_fd_list_finish (connection, &fd_list, result, &error)))
+ {
+ g_autofd int fd = -1;
+ int handle;
+
+ g_variant_get (ret, "(h)", &handle);
+
+ if (-1 == (fd = g_unix_fd_list_get (fd_list, handle, &error)))
+ goto failure;
+
+ dex_promise_resolve_fd (promise, g_steal_fd (&fd));
+ return;
+ }
+
+failure:
+ dex_promise_reject (promise, g_steal_pointer (&error));
+}
+
+static int
+_perf_event_open (GDBusConnection *connection,
+ int cpu,
+ guint stack_size,
+ GError **error)
+{
+ g_autoptr(DexPromise) promise = NULL;
+ g_autoptr(GVariant) options = NULL;
+ g_autofd int perf_fd = -1;
+ struct perf_event_attr attr = {0};
+ gboolean with_mmap2 = TRUE;
+ gboolean use_software = FALSE;
+
+ g_assert (G_IS_DBUS_CONNECTION (connection));
+
+try_again:
+ attr.sample_type = PERF_SAMPLE_IP
+ | PERF_SAMPLE_TID
+ | PERF_SAMPLE_IDENTIFIER
+ | PERF_SAMPLE_CALLCHAIN
+ | PERF_SAMPLE_STACK_USER
+ | PERF_SAMPLE_REGS_USER
+ | PERF_SAMPLE_TIME;
+ attr.wakeup_events = N_WAKEUP_EVENTS;
+ attr.disabled = TRUE;
+ attr.mmap = TRUE;
+ attr.mmap2 = with_mmap2;
+ attr.comm = 1;
+ attr.task = 1;
+ attr.exclude_idle = 1;
+ attr.sample_id_all = 1;
+
+#ifdef HAVE_PERF_CLOCKID
+ attr.clockid = sysprof_clock;
+ attr.use_clockid = 1;
+#endif
+
+ attr.sample_stack_user = stack_size;
+ attr.sample_regs_user = SYSPROF_ARCH_PREFERRED_REGS;
+
+ attr.size = sizeof attr;
+
+ if (use_software)
+ {
+ attr.type = PERF_TYPE_SOFTWARE;
+ attr.config = PERF_COUNT_SW_CPU_CLOCK;
+ attr.sample_period = 1000000;
+ }
+ else
+ {
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_CPU_CYCLES;
+ attr.sample_period = 1200000;
+ }
+
+ options = _sysprof_perf_event_attr_to_variant (&attr);
+ promise = dex_promise_new ();
+
+ g_dbus_connection_call_with_unix_fd_list (connection,
+ "org.gnome.Sysprof3",
+ "/org/gnome/Sysprof3",
+ "org.gnome.Sysprof3.Service",
+ "PerfEventOpen",
+ g_variant_new ("(@a{sv}iiht)",
+ options,
+ -1,
+ cpu,
+ -1,
+ 0),
+ G_VARIANT_TYPE ("(h)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXUINT,
+ NULL,
+ NULL,
+ _perf_event_open_cb,
+ dex_ref (promise));
+
+ if (-1 == (perf_fd = dex_await_fd (dex_ref (promise), error)))
+ {
+ g_clear_pointer (&options, g_variant_unref);
+
+ if (with_mmap2)
+ {
+ with_mmap2 = FALSE;
+ goto try_again;
+ }
+
+ if (use_software == FALSE)
+ {
+ with_mmap2 = TRUE;
+ use_software = TRUE;
+ goto try_again;
+ }
+
+ return -1;
+ }
+
+ return g_steal_fd (&perf_fd);
+}
+
+static void
+call_unwind_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(DexPromise) promise = user_data;
+ g_autoptr(GUnixFDList) out_fd_list = NULL;
+ g_autoptr(GVariant) out_capture_fd = NULL;
+ g_autofd int capture_fd = -1;
+ GError *error = NULL;
+
+ g_assert (IPC_IS_UNWINDER (object));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (DEX_IS_PROMISE (promise));
+
+ if (ipc_unwinder_call_unwind_finish (IPC_UNWINDER (object), &out_capture_fd, &out_fd_list, result, &error) &&
+ -1 != (capture_fd = g_unix_fd_list_get (out_fd_list, g_variant_get_handle (out_capture_fd), &error)))
+ dex_promise_resolve_fd (promise, g_steal_fd (&capture_fd));
+ else
+ dex_promise_reject (promise, error);
+}
+
+static void
+create_unwinder_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(DexPromise) promise = user_data;
+ IpcUnwinder *unwinder;
+ GError *error = NULL;
+
+ if ((unwinder = ipc_unwinder_proxy_new_finish (result, &error)))
+ dex_promise_resolve_object (promise, unwinder);
+ else
+ dex_promise_reject (promise, error);
+}
+
+static IpcUnwinder *
+create_unwinder (GDBusConnection *connection,
+ GError **error)
+{
+ g_autoptr(DexPromise) promise = dex_promise_new ();
+ ipc_unwinder_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE,
+ "org.gnome.Sysprof3",
+ "/org/gnome/Sysprof3/Unwinder",
+ NULL,
+ create_unwinder_cb,
+ dex_ref (promise));
+ return dex_await_object (dex_ref (promise), error);
+}
+
+static DexFuture *
+sysprof_user_sampler_prepare_fiber (gpointer user_data)
+{
+ Prepare *prepare = user_data;
+ g_autoptr(GDBusConnection) connection = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ g_autoptr(GError) error = NULL;
+ GVariantBuilder builder;
+ gboolean all_failed = TRUE;
+ guint n_cpu;
+
+ g_assert (prepare != NULL);
+ g_assert (SYSPROF_IS_RECORDING (prepare->recording));
+ g_assert (SYSPROF_IS_USER_SAMPLER (prepare->sampler));
+
+ if (!(connection = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error)))
+ return dex_future_new_for_error (g_steal_pointer (&error));
+
+ if (!dex_await (_sysprof_recording_add_file (prepare->recording,
+ "/proc/kallsyms",
+ TRUE),
+ &error))
+ {
+ _sysprof_recording_diagnostic (prepare->recording,
+ "Sampler",
+ "Failed to record copy of “kallsyms” to capture: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+
+ n_cpu = g_get_num_processors ();
+ fd_list = g_unix_fd_list_new ();
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(hi)"));
+
+ for (guint i = 0; i < n_cpu; i++)
+ {
+ g_autofd int fd = _perf_event_open (connection, i, prepare->stack_size, &error);
+
+ if (fd == -1)
+ {
+ _sysprof_recording_diagnostic (prepare->recording,
+ "Sampler",
+ "Failed to load Perf event stream for CPU %d with stack size %u: %s",
+ i, prepare->stack_size, error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ int handle = g_unix_fd_list_append (fd_list, fd, &error);
+
+ if (handle == -1)
+ {
+ _sysprof_recording_diagnostic (prepare->recording,
+ "Sampler",
+ "Out of FDs to add to FDList: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ g_array_append_val (prepare->sampler->perf_fds, fd);
+ fd = -1;
+
+ g_variant_builder_add (&builder, "(hi)", handle, i);
+
+ all_failed = FALSE;
+ }
+ }
+ }
+
+ if (!all_failed)
+ {
+ g_autoptr(IpcUnwinder) unwinder = create_unwinder (connection, &error);
+
+ if (unwinder == NULL)
+ {
+ _sysprof_recording_diagnostic (prepare->recording,
+ "Sampler",
+ "Failed to locate unwinder service: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ g_autoptr(DexPromise) promise = dex_promise_new ();
+ int event_fd_handle = g_unix_fd_list_append (fd_list, prepare->sampler->event_fd, NULL);
+ g_autofd int fd = -1;
+
+ ipc_unwinder_call_unwind (unwinder,
+ prepare->stack_size,
+ g_variant_builder_end (&builder),
+ g_variant_new_handle (event_fd_handle),
+ fd_list,
+ NULL,
+ call_unwind_cb,
+ dex_ref (promise));
+
+ fd = dex_await_fd (dex_ref (promise), &error);
+
+ if (fd == -1)
+ {
+ _sysprof_recording_diagnostic (prepare->recording,
+ "Sampler",
+ "Failed to setup user-space unwinder: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ prepare->sampler->capture_fd = g_steal_fd (&fd);
+ }
+ }
+ }
+
+ g_variant_builder_clear (&builder);
+
+ return dex_future_new_for_boolean (TRUE);
+}
+
+static DexFuture *
+sysprof_user_sampler_prepare (SysprofInstrument *instrument,
+ SysprofRecording *recording)
+{
+ SysprofUserSampler *self = (SysprofUserSampler *)instrument;
+ Prepare *prepare;
+
+ g_assert (SYSPROF_IS_INSTRUMENT (instrument));
+ g_assert (SYSPROF_IS_RECORDING (recording));
+
+ prepare = g_new0 (Prepare, 1);
+ prepare->recording = g_object_ref (recording);
+ prepare->sampler = g_object_ref (self);
+ prepare->stack_size = self->stack_size;
+
+ return dex_scheduler_spawn (NULL, 0,
+ sysprof_user_sampler_prepare_fiber,
+ prepare,
+ (GDestroyNotify)prepare_free);
+}
+
+typedef struct _Record
+{
+ SysprofRecording *recording;
+ SysprofUserSampler *sampler;
+ DexFuture *cancellable;
+} Record;
+
+static void
+record_free (Record *record)
+{
+ g_clear_object (&record->recording);
+ g_clear_object (&record->sampler);
+ dex_clear (&record->cancellable);
+ g_free (record);
+}
+
+static DexFuture *
+sysprof_user_sampler_record_fiber (gpointer user_data)
+{
+ SysprofCaptureWriter *writer;
+ Record *record = user_data;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GSource) muxer_source = NULL;
+ guint64 exiting = 1234;
+
+ g_assert (record != NULL);
+ g_assert (SYSPROF_IS_USER_SAMPLER (record->sampler));
+ g_assert (SYSPROF_IS_RECORDING (record->recording));
+ g_assert (DEX_IS_FUTURE (record->cancellable));
+
+ writer = _sysprof_recording_writer (record->recording);
+
+ sysprof_user_sampler_ioctl (record->sampler, TRUE);
+
+ g_debug ("Staring muxer for capture_fd");
+ muxer_source = sysprof_muxer_source_new (g_steal_fd (&record->sampler->capture_fd), writer);
+ g_source_set_static_name (muxer_source, "[stack-muxer]");
+ g_source_attach (muxer_source, NULL);
+
+ if (!dex_await (dex_ref (record->cancellable), &error))
+ g_debug ("UserSampler shutting down for reason: %s", error->message);
+
+ write (record->sampler->event_fd, &exiting, sizeof exiting);
+
+ g_source_destroy (muxer_source);
+
+ sysprof_user_sampler_ioctl (record->sampler, FALSE);
+
+ return dex_future_new_for_boolean (TRUE);
+}
+
+static DexFuture *
+sysprof_user_sampler_record (SysprofInstrument *instrument,
+ SysprofRecording *recording,
+ GCancellable *cancellable)
+{
+ SysprofUserSampler *self = (SysprofUserSampler *)instrument;
+ Record *record;
+
+ g_assert (SYSPROF_IS_INSTRUMENT (instrument));
+ g_assert (SYSPROF_IS_RECORDING (recording));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ record = g_new0 (Record, 1);
+ record->recording = g_object_ref (recording);
+ record->sampler = g_object_ref (self);
+ record->cancellable = dex_cancellable_new_from_cancellable (cancellable);
+
+ return dex_scheduler_spawn (NULL, 0,
+ sysprof_user_sampler_record_fiber,
+ record,
+ (GDestroyNotify)record_free);
+}
+
+static void
+sysprof_user_sampler_finalize (GObject *object)
+{
+ SysprofUserSampler *self = (SysprofUserSampler *)object;
+
+ g_clear_pointer (&self->perf_fds, g_array_unref);
+
+ g_clear_fd (&self->capture_fd, NULL);
+ g_clear_fd (&self->event_fd, NULL);
+
+ G_OBJECT_CLASS (sysprof_user_sampler_parent_class)->finalize (object);
+}
+
+static void
+sysprof_user_sampler_class_init (SysprofUserSamplerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass);
+
+ object_class->finalize = sysprof_user_sampler_finalize;
+
+ instrument_class->list_required_policy = sysprof_user_sampler_list_required_policy;
+ instrument_class->prepare = sysprof_user_sampler_prepare;
+ instrument_class->record = sysprof_user_sampler_record;
+}
+
+static void
+sysprof_user_sampler_init (SysprofUserSampler *self)
+{
+ self->capture_fd = -1;
+ self->event_fd = eventfd (0, EFD_CLOEXEC);
+
+ self->perf_fds = g_array_new (FALSE, FALSE, sizeof (int));
+ g_array_set_clear_func (self->perf_fds, close_fd);
+}
+
+SysprofInstrument *
+sysprof_user_sampler_new (guint stack_size)
+{
+ SysprofUserSampler *self;
+
+ g_return_val_if_fail (stack_size > 0, NULL);
+ g_return_val_if_fail (stack_size % sysprof_getpagesize () == 0, NULL);
+
+ self = g_object_new (SYSPROF_TYPE_USER_SAMPLER, NULL);
+ self->stack_size = stack_size;
+
+ return SYSPROF_INSTRUMENT (self);
+}
diff --git a/src/libsysprof/sysprof-user-sampler.h b/src/libsysprof/sysprof-user-sampler.h
new file mode 100644
index 00000000..d39e6095
--- /dev/null
+++ b/src/libsysprof/sysprof-user-sampler.h
@@ -0,0 +1,43 @@
+/*
+ * sysprof-user-sampler.h
+ *
+ * Copyright 2024 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 "sysprof-instrument.h"
+
+G_BEGIN_DECLS
+
+#define SYSPROF_TYPE_USER_SAMPLER (sysprof_user_sampler_get_type())
+#define SYSPROF_IS_USER_SAMPLER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_USER_SAMPLER)
+#define SYSPROF_USER_SAMPLER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_USER_SAMPLER, SysprofUserSampler)
+#define SYSPROF_USER_SAMPLER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_USER_SAMPLER, SysprofUserSamplerClass)
+
+typedef struct _SysprofUserSampler SysprofUserSampler;
+typedef struct _SysprofUserSamplerClass SysprofUserSamplerClass;
+
+SYSPROF_AVAILABLE_IN_47
+GType sysprof_user_sampler_get_type (void) G_GNUC_CONST;
+SYSPROF_AVAILABLE_IN_47
+SysprofInstrument *sysprof_user_sampler_new (guint stack_size);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofUserSampler, g_object_unref)
+
+G_END_DECLS
diff --git a/src/libsysprof/sysprof.h b/src/libsysprof/sysprof.h
index d30f9fd4..514e332b 100644
--- a/src/libsysprof/sysprof.h
+++ b/src/libsysprof/sysprof.h
@@ -89,6 +89,7 @@ G_BEGIN_DECLS
# include "sysprof-time-span.h"
# include "sysprof-tracefd-consumer.h"
# include "sysprof-tracer.h"
+# include "sysprof-user-sampler.h"
#undef SYSPROF_INSIDE
G_END_DECLS
--
2.45.2

View File

@ -0,0 +1,60 @@
From f7118874cfac04b8febf38ee9b073b6d46cc3f08 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Sun, 3 Nov 2024 10:54:57 -0800
Subject: [PATCH 18/31] sysprof-cli: add support for live unwinding
This allows you to specify --stack-size=(multiple_of_page_size) to unwind
from captured stack contents. It will use the new SysprofUserSampler to
unwind stack traces via sysprof-live-unwinder.
---
src/sysprof-cli/sysprof-cli.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/sysprof-cli/sysprof-cli.c b/src/sysprof-cli/sysprof-cli.c
index e00bd6b1..1c9ce928 100644
--- a/src/sysprof-cli/sysprof-cli.c
+++ b/src/sysprof-cli/sysprof-cli.c
@@ -303,6 +303,7 @@ main (int argc,
gboolean scheduler_details = FALSE;
gboolean system_bus = FALSE;
gboolean session_bus = FALSE;
+ int stack_size = 0;
int pid = -1;
int fd;
int flags;
@@ -335,6 +336,7 @@ main (int argc,
{ "version", 0, 0, G_OPTION_ARG_NONE, &version, N_("Print the sysprof-cli version and exit") },
{ "buffer-size", 0, 0, G_OPTION_ARG_INT, &n_buffer_pages, N_("The size of the buffer in pages (1 = 1 page)") },
{ "monitor-bus", 0, 0, G_OPTION_ARG_STRING_ARRAY, &monitor_bus, N_("Additional D-Bus address to monitor") },
+ { "stack-size", 0, 0, G_OPTION_ARG_INT, &stack_size, N_("Stack size to copy for unwinding in user-space") },
{ NULL }
};
@@ -379,6 +381,10 @@ Examples:\n\
\n\
# Merge multiple syscap files into one\n\
sysprof-cli --merge a.syscap b.syscap > c.syscap\n\
+\n\
+ # Unwind by capturing stack/register contents instead of frame-pointers\n\
+ # where the stack-size is a multiple of page-size\n\
+ sysprof-cli --stack-size=8192\n\
"));
if (!g_option_context_parse (context, &argc, &argv, &error))
@@ -533,7 +539,12 @@ Examples:\n\
sysprof_profiler_add_instrument (profiler, sysprof_system_logs_new ());
if (!no_perf)
- sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
+ {
+ if (stack_size == 0)
+ sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
+ else
+ sysprof_profiler_add_instrument (profiler, sysprof_user_sampler_new (stack_size));
+ }
if (!no_disk)
sysprof_profiler_add_instrument (profiler, sysprof_disk_usage_new ());
--
2.45.2

View File

@ -0,0 +1,506 @@
From f02e19820e5a3b223f2b563946daa80693c98ca2 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Sun, 3 Nov 2024 10:57:58 -0800
Subject: [PATCH 19/31] sysprof: add UI for live unwinding
This adds UI to specify the amount of stack contents to copy along with
the CPU registers so that you may unwind in user-space.
---
src/sysprof/meson.build | 1 +
src/sysprof/sysprof-greeter.c | 32 +++++
src/sysprof/sysprof-greeter.ui | 67 +++++++++++
src/sysprof/sysprof-recording-template.c | 41 ++++++-
src/sysprof/sysprof-stack-size.c | 141 +++++++++++++++++++++++
src/sysprof/sysprof-stack-size.h | 35 ++++++
6 files changed, 316 insertions(+), 1 deletion(-)
create mode 100644 src/sysprof/sysprof-stack-size.c
create mode 100644 src/sysprof/sysprof-stack-size.h
diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build
index ca42ead3..ab6a701a 100644
--- a/src/sysprof/meson.build
+++ b/src/sysprof/meson.build
@@ -57,6 +57,7 @@ sysprof_sources = [
'sysprof-sidebar.c',
'sysprof-single-model.c',
'sysprof-split-layer.c',
+ 'sysprof-stack-size.c',
'sysprof-storage-section.c',
'sysprof-symbol-label.c',
'sysprof-task-row.c',
diff --git a/src/sysprof/sysprof-greeter.c b/src/sysprof/sysprof-greeter.c
index 72f4dd5d..52eff370 100644
--- a/src/sysprof/sysprof-greeter.c
+++ b/src/sysprof/sysprof-greeter.c
@@ -31,6 +31,7 @@
#include "sysprof-power-profiles.h"
#include "sysprof-recording-pad.h"
#include "sysprof-recording-template.h"
+#include "sysprof-stack-size.h"
#include "sysprof-window.h"
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureWriter, sysprof_capture_writer_unref)
@@ -56,6 +57,7 @@ struct _SysprofGreeter
GtkSwitch *bundle_symbols;
GtkButton *record_to_memory;
AdwComboRow *power_combo;
+ AdwComboRow *sample_user_stack_size;
SysprofRecordingTemplate *recording_template;
};
@@ -455,6 +457,26 @@ translate_power_profile (GtkStringObject *strobj)
return g_strdup (str);
}
+static void
+on_stack_size_changed_cb (SysprofGreeter *self,
+ GParamSpec *pspec,
+ AdwComboRow *row)
+{
+ GObject *item;
+
+ g_assert (SYSPROF_IS_GREETER (self));
+ g_assert (ADW_IS_COMBO_ROW (row));
+
+ if ((item = adw_combo_row_get_selected_item (row)))
+ {
+ guint stack_size = sysprof_stack_size_get_size (SYSPROF_STACK_SIZE (item));
+
+ g_object_set (self->recording_template,
+ "stack-size", stack_size,
+ NULL);
+ }
+}
+
static void
sysprof_greeter_dispose (GObject *object)
{
@@ -492,6 +514,7 @@ sysprof_greeter_class_init (SysprofGreeterClass *klass)
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, recording_template);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_javascript_stacks);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_native_stacks);
+ gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_user_stack_size);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sidebar_list_box);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, view_stack);
@@ -507,6 +530,7 @@ sysprof_greeter_class_init (SysprofGreeterClass *klass)
g_type_ensure (SYSPROF_TYPE_ENTRY_POPOVER);
g_type_ensure (SYSPROF_TYPE_RECORDING_TEMPLATE);
+ g_type_ensure (SYSPROF_TYPE_STACK_SIZE);
}
static void
@@ -540,6 +564,14 @@ sysprof_greeter_init (SysprofGreeter *self)
gtk_list_box_select_row (self->sidebar_list_box, row);
sidebar_row_activated_cb (self, row, self->sidebar_list_box);
+ g_signal_connect_object (self->sample_user_stack_size,
+ "notify::selected-item",
+ G_CALLBACK (on_stack_size_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ /* Set to 16KB */
+ adw_combo_row_set_selected (self->sample_user_stack_size, 1);
+
gtk_widget_grab_focus (GTK_WIDGET (self->record_to_memory));
}
diff --git a/src/sysprof/sysprof-greeter.ui b/src/sysprof/sysprof-greeter.ui
index 35e790f5..f7ebbc29 100644
--- a/src/sysprof/sysprof-greeter.ui
+++ b/src/sysprof/sysprof-greeter.ui
@@ -106,6 +106,41 @@
</child>
</object>
</child>
+ <child>
+ <object class="AdwExpanderRow">
+ <property name="title" translatable="yes">Unwind Stacks in User Space</property>
+ <property name="subtitle" translatable="yes">Copy stack contents and registers for unwinding in user-space</property>
+ <property name="expanded" bind-source="sample_user_stack" bind-property="active" bind-flags="sync-create|bidirectional"/>
+ <child type="action">
+ <object class="GtkSwitch" id="sample_user_stack">
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <property name="active" bind-source="recording_template" bind-flags="bidirectional|sync-create" bind-property="user-stacks"/>
+ </object>
+ </child>
+ <child>
+ <object class="AdwComboRow" id="sample_user_stack_size">
+ <property name="title" translatable="yes">Stack Size</property>
+ <property name="subtitle" translatable="yes">The number of bytes to copy from the stack</property>
+ <property name="model">stack_sizes</property>
+ <property name="expression">
+ <lookup name="label" type="SysprofStackSize"/>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">Unwinding in user-space has considerable overhead but may help in situations where frame-pointers are unavailable.</property>
+ <property name="xalign">0</property>
+ <property name="margin-top">8</property>
+ <style>
+ <class name="caption"/>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
</object>
</child>
<child>
@@ -664,4 +699,36 @@
</object>
<object class="GtkStringList" id="envvars">
</object>
+ <object class="GListStore" id="stack_sizes">
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">8 KB</property>
+ <property name="size">8192</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">16 KB</property>
+ <property name="size">16384</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">24 KB</property>
+ <property name="size">24576</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">32 KB</property>
+ <property name="size">32768</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">64 KB</property>
+ <property name="size">65536</property>
+ </object>
+ </child>
+ </object>
</interface>
diff --git a/src/sysprof/sysprof-recording-template.c b/src/sysprof/sysprof-recording-template.c
index 50f6c957..ee4d4f01 100644
--- a/src/sysprof/sysprof-recording-template.c
+++ b/src/sysprof/sysprof-recording-template.c
@@ -22,6 +22,8 @@
#include "sysprof-recording-template.h"
+#define DEFAULT_STACK_SIZE (4096*4)
+
struct _SysprofRecordingTemplate
{
GObject parent_instance;
@@ -31,6 +33,8 @@ struct _SysprofRecordingTemplate
char *power_profile;
char **environ;
+ guint stack_size;
+
guint battery_charge : 1;
guint bundle_symbols : 1;
guint clear_environ : 1;
@@ -49,6 +53,7 @@ struct _SysprofRecordingTemplate
guint session_bus : 1;
guint system_bus : 1;
guint system_log : 1;
+ guint user_stacks : 1;
};
enum {
@@ -73,8 +78,10 @@ enum {
PROP_POWER_PROFILE,
PROP_SCHEDULER_DETAILS,
PROP_SESSION_BUS,
+ PROP_STACK_SIZE,
PROP_SYSTEM_BUS,
PROP_SYSTEM_LOG,
+ PROP_USER_STACKS,
N_PROPS
};
@@ -185,6 +192,10 @@ sysprof_recording_template_get_property (GObject *object,
g_value_set_boolean (value, self->session_bus);
break;
+ case PROP_STACK_SIZE:
+ g_value_set_uint (value, self->stack_size);
+ break;
+
case PROP_SYSTEM_BUS:
g_value_set_boolean (value, self->system_bus);
break;
@@ -193,6 +204,10 @@ sysprof_recording_template_get_property (GObject *object,
g_value_set_boolean (value, self->system_log);
break;
+ case PROP_USER_STACKS:
+ g_value_set_boolean (value, self->user_stacks);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -289,6 +304,10 @@ sysprof_recording_template_set_property (GObject *object,
self->session_bus = g_value_get_boolean (value);
break;
+ case PROP_STACK_SIZE:
+ self->stack_size = g_value_get_uint (value);
+ break;
+
case PROP_SYSTEM_BUS:
self->system_bus = g_value_get_boolean (value);
break;
@@ -297,6 +316,10 @@ sysprof_recording_template_set_property (GObject *object,
self->system_log = g_value_get_boolean (value);
break;
+ case PROP_USER_STACKS:
+ self->user_stacks = g_value_get_boolean (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -421,6 +444,16 @@ sysprof_recording_template_class_init (SysprofRecordingTemplateClass *klass)
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ properties[PROP_USER_STACKS] =
+ g_param_spec_boolean ("user-stacks", NULL, NULL,
+ FALSE,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_STACK_SIZE] =
+ g_param_spec_uint ("stack-size", NULL, NULL,
+ 0, G_MAXUINT, DEFAULT_STACK_SIZE,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -439,6 +472,7 @@ sysprof_recording_template_init (SysprofRecordingTemplate *self)
self->system_log = TRUE;
self->command_line = g_strdup ("");
self->cwd = g_strdup("");
+ self->stack_size = DEFAULT_STACK_SIZE;
}
SysprofRecordingTemplate *
@@ -619,7 +653,12 @@ sysprof_recording_template_apply (SysprofRecordingTemplate *self,
sysprof_profiler_add_instrument (profiler, sysprof_memory_usage_new ());
if (self->native_stacks)
- sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
+ {
+ if (self->user_stacks)
+ sysprof_profiler_add_instrument (profiler, sysprof_user_sampler_new (self->stack_size));
+ else
+ sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
+ }
if (self->network_usage)
sysprof_profiler_add_instrument (profiler, sysprof_network_usage_new ());
diff --git a/src/sysprof/sysprof-stack-size.c b/src/sysprof/sysprof-stack-size.c
new file mode 100644
index 00000000..d6652766
--- /dev/null
+++ b/src/sysprof/sysprof-stack-size.c
@@ -0,0 +1,141 @@
+/*
+ * sysprof-stack-size.c
+ *
+ * Copyright 2024 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-stack-size.h"
+
+struct _SysprofStackSize
+{
+ GObject parent_instance;
+ char *label;
+ guint size;
+};
+
+enum {
+ PROP_0,
+ PROP_SIZE,
+ PROP_LABEL,
+ N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (SysprofStackSize, sysprof_stack_size, G_TYPE_OBJECT)
+
+static GParamSpec *properties[N_PROPS];
+
+static void
+sysprof_stack_size_finalize (GObject *object)
+{
+ SysprofStackSize *self = (SysprofStackSize *)object;
+
+ g_clear_pointer (&self->label, g_free);
+
+ G_OBJECT_CLASS (sysprof_stack_size_parent_class)->finalize (object);
+}
+
+static void
+sysprof_stack_size_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SysprofStackSize *self = SYSPROF_STACK_SIZE (object);
+
+ switch (prop_id)
+ {
+ case PROP_SIZE:
+ g_value_set_uint (value, self->size);
+ break;
+
+ case PROP_LABEL:
+ g_value_set_string (value, self->label);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+sysprof_stack_size_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SysprofStackSize *self = SYSPROF_STACK_SIZE (object);
+
+ switch (prop_id)
+ {
+ case PROP_SIZE:
+ self->size = g_value_get_uint (value);
+ break;
+
+ case PROP_LABEL:
+ g_set_str (&self->label, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+sysprof_stack_size_class_init (SysprofStackSizeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = sysprof_stack_size_finalize;
+ object_class->get_property = sysprof_stack_size_get_property;
+ object_class->set_property = sysprof_stack_size_set_property;
+
+ properties[PROP_SIZE] =
+ g_param_spec_uint ("size", NULL, NULL,
+ 0, (4096*32), 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+sysprof_stack_size_init (SysprofStackSize *self)
+{
+}
+
+guint
+sysprof_stack_size_get_size (SysprofStackSize *self)
+{
+ g_return_val_if_fail (SYSPROF_IS_STACK_SIZE (self), 0);
+
+ return self->size;
+}
+
+const char *
+sysprof_stack_size_get_label (SysprofStackSize *self)
+{
+ g_return_val_if_fail (SYSPROF_IS_STACK_SIZE (self), NULL);
+
+ return self->label;
+}
diff --git a/src/sysprof/sysprof-stack-size.h b/src/sysprof/sysprof-stack-size.h
new file mode 100644
index 00000000..5dd7f9c2
--- /dev/null
+++ b/src/sysprof/sysprof-stack-size.h
@@ -0,0 +1,35 @@
+/*
+ * sysprof-stack-size.h
+ *
+ * Copyright 2024 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>
+
+G_BEGIN_DECLS
+
+#define SYSPROF_TYPE_STACK_SIZE (sysprof_stack_size_get_type())
+
+G_DECLARE_FINAL_TYPE (SysprofStackSize, sysprof_stack_size, SYSPROF, STACK_SIZE, GObject)
+
+guint sysprof_stack_size_get_size (SysprofStackSize *self);
+const char *sysprof_stack_size_get_label (SysprofStackSize *self);
+
+G_END_DECLS
--
2.45.2

View File

@ -0,0 +1,49 @@
From 51c7529c515c2e5c4362676e44f2679ce8cc66db Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Mon, 4 Nov 2024 14:21:15 -0800
Subject: [PATCH 20/31] sysprof-live-unwinder: ifdef unused code off x86
Fixes a compiler warning about unused functions.
---
src/sysprof-live-unwinder/sysprof-live-process.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/sysprof-live-unwinder/sysprof-live-process.c b/src/sysprof-live-unwinder/sysprof-live-process.c
index 7932048b..90fd2633 100644
--- a/src/sysprof-live-unwinder/sysprof-live-process.c
+++ b/src/sysprof-live-unwinder/sysprof-live-process.c
@@ -80,6 +80,7 @@ typedef struct _SysprofUnwinder
static SysprofUnwinder *current_unwinder;
+#if defined(__x86_64__) || defined(__i386__)
static inline GPid
sysprof_unwinder_next_thread (Dwfl *dwfl,
void *user_data,
@@ -230,6 +231,7 @@ sysprof_unwinder_frame_cb (Dwfl_Frame *frame,
return DWARF_CB_OK;
}
+#endif
static inline guint
sysprof_unwind (SysprofLiveProcess *self,
@@ -406,6 +408,7 @@ sysprof_live_process_is_active (SysprofLiveProcess *self)
return self->fd > -1;
}
+#if defined(__x86_64__) || defined(__i386__)
static Dwfl *
sysprof_live_process_get_dwfl (SysprofLiveProcess *self)
{
@@ -440,6 +443,7 @@ sysprof_live_process_get_dwfl (SysprofLiveProcess *self)
return self->dwfl;
}
+#endif
guint
sysprof_live_process_unwind (SysprofLiveProcess *self,
--
2.45.2

View File

@ -0,0 +1,58 @@
From 7ae54a2e334dead967216f17455026fbcf256186 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Mon, 4 Nov 2024 14:25:07 -0800
Subject: [PATCH 21/31] sysprof: only show user stack sampling on x86
That is the only place it works currently (and is necessary).
---
src/sysprof/sysprof-greeter.c | 6 ++++++
src/sysprof/sysprof-greeter.ui | 2 +-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/sysprof/sysprof-greeter.c b/src/sysprof/sysprof-greeter.c
index 52eff370..e0313e81 100644
--- a/src/sysprof/sysprof-greeter.c
+++ b/src/sysprof/sysprof-greeter.c
@@ -58,6 +58,7 @@ struct _SysprofGreeter
GtkButton *record_to_memory;
AdwComboRow *power_combo;
AdwComboRow *sample_user_stack_size;
+ AdwExpanderRow *user_stacks;
SysprofRecordingTemplate *recording_template;
};
@@ -516,6 +517,7 @@ sysprof_greeter_class_init (SysprofGreeterClass *klass)
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_native_stacks);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_user_stack_size);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sidebar_list_box);
+ gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, user_stacks);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, view_stack);
gtk_widget_class_bind_template_callback (widget_class, sidebar_row_activated_cb);
@@ -572,6 +574,10 @@ sysprof_greeter_init (SysprofGreeter *self)
/* Set to 16KB */
adw_combo_row_set_selected (self->sample_user_stack_size, 1);
+#if !defined(__x86_64__) && !defined(__i386__)
+ gtk_widget_set_visible (GTK_WIDGET (self->user_stacks), FALSE);
+#endif
+
gtk_widget_grab_focus (GTK_WIDGET (self->record_to_memory));
}
diff --git a/src/sysprof/sysprof-greeter.ui b/src/sysprof/sysprof-greeter.ui
index f7ebbc29..92ade34d 100644
--- a/src/sysprof/sysprof-greeter.ui
+++ b/src/sysprof/sysprof-greeter.ui
@@ -107,7 +107,7 @@
</object>
</child>
<child>
- <object class="AdwExpanderRow">
+ <object class="AdwExpanderRow" id="user_stacks">
<property name="title" translatable="yes">Unwind Stacks in User Space</property>
<property name="subtitle" translatable="yes">Copy stack contents and registers for unwinding in user-space</property>
<property name="expanded" bind-source="sample_user_stack" bind-property="active" bind-flags="sync-create|bidirectional"/>
--
2.45.2

View File

@ -0,0 +1,30 @@
From be843d84b49f7cd7ce15352ab187e4197cdd887e Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Fri, 8 Nov 2024 11:42:04 -0800
Subject: [PATCH 22/31] libsysprof: check for PERF_REG_EXTENDED_MASK
availability
---
src/libsysprof/sysprof-user-sampler.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/libsysprof/sysprof-user-sampler.c b/src/libsysprof/sysprof-user-sampler.c
index 0e3afeae..a1418596 100644
--- a/src/libsysprof/sysprof-user-sampler.c
+++ b/src/libsysprof/sysprof-user-sampler.c
@@ -48,7 +48,11 @@
#define SYSPROF_ARCH_PREFERRED_REGS DWARF_NEEDED_REGS
/* TODO: add other architectures, imitating the linux tools/perf tree */
#else
-# define SYSPROF_ARCH_PREFERRED_REGS PERF_REG_EXTENDED_MASK
+# ifdef PERF_REG_EXTENDED_MASK
+# define SYSPROF_ARCH_PREFERRED_REGS PERF_REG_EXTENDED_MASK
+# else
+# define SYSPROF_ARCH_PREFERRED_REGS 0
+# endif
#endif /* _ASM_{arch}_PERF_REGS_H */
#define N_WAKEUP_EVENTS 149
--
2.45.2

View File

@ -0,0 +1,38 @@
From ed19a1b29cf6adc628432128bf6162c1446d5a46 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Tue, 12 Nov 2024 14:45:57 -0800
Subject: [PATCH 23/31] sysprof-live-unwinder: fix source func prototype
While this looks like a GSource, the implementation type requires that
it actually be a GUnixFDSourceFunc.
---
src/sysprof-live-unwinder/main.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/sysprof-live-unwinder/main.c b/src/sysprof-live-unwinder/main.c
index 9e2733ae..e14eaf6c 100644
--- a/src/sysprof-live-unwinder/main.c
+++ b/src/sysprof-live-unwinder/main.c
@@ -642,7 +642,9 @@ bump_to_max_fd_limit (void)
}
static gboolean
-exit_callback (gpointer user_data)
+exit_callback (int fd,
+ GIOCondition condition,
+ gpointer user_data)
{
g_main_loop_quit (user_data);
return G_SOURCE_REMOVE;
@@ -738,7 +740,7 @@ Examples:\n\
g_autoptr(GSource) exit_source = g_unix_fd_source_new (event_fd, G_IO_IN);
g_source_set_callback (exit_source,
- exit_callback,
+ (GSourceFunc)exit_callback,
g_main_loop_ref (main_loop),
(GDestroyNotify) g_main_loop_unref);
g_source_attach (exit_source, NULL);
--
2.45.2

View File

@ -0,0 +1,28 @@
From 4b28282e30ee9ee483d3ed31a27956a5b35d2e95 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 15:29:15 -0800
Subject: [PATCH 24/31] sysprof-live-unwinder: handle large stack unwind sizes
---
src/sysprof-live-unwinder/sysprof-live-unwinder.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/sysprof-live-unwinder/sysprof-live-unwinder.c b/src/sysprof-live-unwinder/sysprof-live-unwinder.c
index c3b954b2..da77b0b0 100644
--- a/src/sysprof-live-unwinder/sysprof-live-unwinder.c
+++ b/src/sysprof-live-unwinder/sysprof-live-unwinder.c
@@ -377,6 +377,11 @@ sysprof_live_unwinder_process_sampled_with_stack (SysprofLiveUnwinder *s
return;
}
+ /* We seem to get values > stack_size, which perhaps indicates we can
+ * sometimes discover if we would not have gotten enough stack to unwind.
+ */
+ stack_dyn_size = MIN (stack_dyn_size, stack_size);
+
live_pid = sysprof_live_unwinder_find_pid (self, pid, TRUE);
/* Copy addresses over (which might be kernel, context-switch, etc until
--
2.45.2

View File

@ -0,0 +1,67 @@
From 767e26c0aa2379312da5b029f924f765d90edce8 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 15:46:01 -0800
Subject: [PATCH 25/31] unwinder: wait for completion of subprocess
---
src/sysprofd/ipc-unwinder-impl.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/src/sysprofd/ipc-unwinder-impl.c b/src/sysprofd/ipc-unwinder-impl.c
index 7f218de6..4341516b 100644
--- a/src/sysprofd/ipc-unwinder-impl.c
+++ b/src/sysprofd/ipc-unwinder-impl.c
@@ -46,6 +46,25 @@ child_setup (gpointer data)
prctl (PR_SET_PDEATHSIG, SIGKILL);
}
+static void
+ipc_unwinder_impl_wait_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSubprocess *subprocess = (GSubprocess *)object;
+ g_autoptr(IpcUnwinderImpl) self = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (G_IS_SUBPROCESS (subprocess));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IPC_IS_UNWINDER_IMPL (self));
+
+ if (!g_subprocess_wait_check_finish (subprocess, result, &error))
+ g_warning ("wait_check failure: %s", error->message);
+ else
+ g_info ("sysprof-live-unwinder exited");
+}
+
static gboolean
ipc_unwinder_impl_handle_unwind (IpcUnwinder *unwinder,
GDBusMethodInvocation *invocation,
@@ -155,16 +174,23 @@ ipc_unwinder_impl_handle_unwind (IpcUnwinder *unwinder,
if (!(subprocess = g_subprocess_launcher_spawnv (launcher, (const char * const *)argv->pdata, &error)))
{
+ g_critical ("Failed to start sysprof-live-unwinder: %s", error->message);
g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
return TRUE;
}
+ g_message ("sysprof-live-unwinder started as process %s",
+ g_subprocess_get_identifier (subprocess));
+
ipc_unwinder_complete_unwind (unwinder,
g_steal_pointer (&invocation),
out_fd_list,
g_variant_new_handle (capture_fd_handle));
- g_subprocess_wait_async (subprocess, NULL, NULL, NULL);
+ g_subprocess_wait_check_async (subprocess,
+ NULL,
+ ipc_unwinder_impl_wait_cb,
+ g_object_ref (unwinder));
return TRUE;
}
--
2.45.2

View File

@ -0,0 +1,227 @@
From 12d0c969b83878d69f36255004b0dae6736a6c03 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 6 Nov 2024 15:09:13 -0800
Subject: [PATCH 26/31] sysprof-user-sampler: implement await for FDs
This allows us to not need libdex 0.9+ for use by the sampler.
---
src/libsysprof/meson.build | 1 +
src/libsysprof/sysprof-fd-private.h | 39 ++++++++++++++++
src/libsysprof/sysprof-fd.c | 67 +++++++++++++++++++++++++++
src/libsysprof/sysprof-user-sampler.c | 33 +++++++++++--
4 files changed, 136 insertions(+), 4 deletions(-)
create mode 100644 src/libsysprof/sysprof-fd-private.h
create mode 100644 src/libsysprof/sysprof-fd.c
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index e49c3a37..2ae977ca 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -144,6 +144,7 @@ libsysprof_private_sources = [
'sysprof-document-symbols.c',
'sysprof-elf-loader.c',
'sysprof-elf.c',
+ 'sysprof-fd.c',
'sysprof-leak-detector.c',
'sysprof-maps-parser.c',
'sysprof-mount-device.c',
diff --git a/src/libsysprof/sysprof-fd-private.h b/src/libsysprof/sysprof-fd-private.h
new file mode 100644
index 00000000..1d4dfabc
--- /dev/null
+++ b/src/libsysprof/sysprof-fd-private.h
@@ -0,0 +1,39 @@
+/* sysprof-fd-private.h
+ *
+ * Copyright 2024 Christian Hergert <chergert@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser 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: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define SYSPROF_TYPE_FD (sysprof_fd_get_type())
+
+typedef struct _SysprofFD SysprofFD;
+
+GType sysprof_fd_get_type (void) G_GNUC_CONST;
+int sysprof_fd_peek (const SysprofFD *fd);
+int sysprof_fd_steal (SysprofFD *fd);
+SysprofFD *sysprof_fd_dup (const SysprofFD *fd);
+void sysprof_fd_free (SysprofFD *fd);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofFD, sysprof_fd_free)
+
+G_END_DECLS
diff --git a/src/libsysprof/sysprof-fd.c b/src/libsysprof/sysprof-fd.c
new file mode 100644
index 00000000..5e34f8d9
--- /dev/null
+++ b/src/libsysprof/sysprof-fd.c
@@ -0,0 +1,67 @@
+/* sysprof-fd.c
+ *
+ * Copyright 2024 Christian Hergert <chergert@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser 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: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+
+#include "sysprof-fd-private.h"
+
+int
+sysprof_fd_peek (const SysprofFD *fd)
+{
+ if (fd == NULL)
+ return -1;
+
+ return *(int *)fd;
+}
+
+int
+sysprof_fd_steal (SysprofFD *fd)
+{
+ if (fd == NULL)
+ return -1;
+
+ return g_steal_fd ((int *)fd);
+}
+
+void
+sysprof_fd_free (SysprofFD *fd)
+{
+ int real = sysprof_fd_steal (fd);
+ if (real != -1)
+ close (real);
+ g_free (fd);
+}
+
+SysprofFD *
+sysprof_fd_dup (const SysprofFD *fd)
+{
+ int real = sysprof_fd_peek (fd);
+
+ if (real == -1)
+ return NULL;
+
+ real = dup (real);
+
+ return g_memdup2 (&real, sizeof real);
+}
+
+G_DEFINE_BOXED_TYPE (SysprofFD, sysprof_fd, sysprof_fd_dup, sysprof_fd_free)
diff --git a/src/libsysprof/sysprof-user-sampler.c b/src/libsysprof/sysprof-user-sampler.c
index a1418596..44b4d318 100644
--- a/src/libsysprof/sysprof-user-sampler.c
+++ b/src/libsysprof/sysprof-user-sampler.c
@@ -32,6 +32,7 @@
#include "sysprof-recording-private.h"
#include "sysprof-user-sampler.h"
#include "sysprof-muxer-source.h"
+#include "sysprof-fd-private.h"
#include "ipc-unwinder.h"
@@ -85,6 +86,30 @@ close_fd (gpointer data)
}
}
+static void
+promise_resolve_fd (DexPromise *promise,
+ int fd)
+{
+ GValue gvalue = {SYSPROF_TYPE_FD, {{.v_pointer = &fd}, {.v_int = 0}}};
+ dex_promise_resolve (promise, &gvalue);
+}
+
+static int
+await_fd (DexFuture *future,
+ GError **error)
+{
+ SysprofFD *fd = dex_await_boxed (future, error);
+ int ret = -1;
+
+ if (fd != NULL)
+ {
+ ret = sysprof_fd_steal (fd);
+ sysprof_fd_free (fd);
+ }
+
+ return ret;
+}
+
static void
sysprof_user_sampler_ioctl (SysprofUserSampler *self,
gboolean enable)
@@ -149,7 +174,7 @@ _perf_event_open_cb (GObject *object,
if (-1 == (fd = g_unix_fd_list_get (fd_list, handle, &error)))
goto failure;
- dex_promise_resolve_fd (promise, g_steal_fd (&fd));
+ promise_resolve_fd (promise, g_steal_fd (&fd));
return;
}
@@ -234,7 +259,7 @@ try_again:
_perf_event_open_cb,
dex_ref (promise));
- if (-1 == (perf_fd = dex_await_fd (dex_ref (promise), error)))
+ if (-1 == (perf_fd = await_fd (dex_ref (promise), error)))
{
g_clear_pointer (&options, g_variant_unref);
@@ -274,7 +299,7 @@ call_unwind_cb (GObject *object,
if (ipc_unwinder_call_unwind_finish (IPC_UNWINDER (object), &out_capture_fd, &out_fd_list, result, &error) &&
-1 != (capture_fd = g_unix_fd_list_get (out_fd_list, g_variant_get_handle (out_capture_fd), &error)))
- dex_promise_resolve_fd (promise, g_steal_fd (&capture_fd));
+ promise_resolve_fd (promise, g_steal_fd (&capture_fd));
else
dex_promise_reject (promise, error);
}
@@ -406,7 +431,7 @@ sysprof_user_sampler_prepare_fiber (gpointer user_data)
call_unwind_cb,
dex_ref (promise));
- fd = dex_await_fd (dex_ref (promise), &error);
+ fd = await_fd (dex_ref (promise), &error);
if (fd == -1)
{
--
2.45.2

View File

@ -0,0 +1,276 @@
From 6812ec432141fbdf0754e90d1e7a3d5667b14bf0 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 15:40:52 -0800
Subject: [PATCH 27/31] libsysprof: provide unwind pipe from client
We don't need a socketpair for this. Additionally, things seem to work
better from the service when the client provides the pipe. Otherwise, when
running as a dbus service I often have issues with things getting closed
out from under us.
---
src/libsysprof/sysprof-user-sampler.c | 65 ++++++++++++--------
src/sysprofd/ipc-unwinder-impl.c | 46 +++-----------
src/sysprofd/org.gnome.Sysprof3.Unwinder.xml | 2 +-
3 files changed, 48 insertions(+), 65 deletions(-)
diff --git a/src/libsysprof/sysprof-user-sampler.c b/src/libsysprof/sysprof-user-sampler.c
index 44b4d318..6079708e 100644
--- a/src/libsysprof/sysprof-user-sampler.c
+++ b/src/libsysprof/sysprof-user-sampler.c
@@ -20,6 +20,8 @@
#include "config.h"
+#include <fcntl.h>
+
#include <sys/ioctl.h>
#include <sys/eventfd.h>
@@ -62,7 +64,8 @@ struct _SysprofUserSampler
{
SysprofInstrument parent_instance;
GArray *perf_fds;
- int capture_fd;
+ int capture_fd_read;
+ int capture_fd_write;
int event_fd;
guint stack_size;
};
@@ -289,17 +292,14 @@ call_unwind_cb (GObject *object,
{
g_autoptr(DexPromise) promise = user_data;
g_autoptr(GUnixFDList) out_fd_list = NULL;
- g_autoptr(GVariant) out_capture_fd = NULL;
- g_autofd int capture_fd = -1;
GError *error = NULL;
g_assert (IPC_IS_UNWINDER (object));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (DEX_IS_PROMISE (promise));
- if (ipc_unwinder_call_unwind_finish (IPC_UNWINDER (object), &out_capture_fd, &out_fd_list, result, &error) &&
- -1 != (capture_fd = g_unix_fd_list_get (out_fd_list, g_variant_get_handle (out_capture_fd), &error)))
- promise_resolve_fd (promise, g_steal_fd (&capture_fd));
+ if (ipc_unwinder_call_unwind_finish (IPC_UNWINDER (object), &out_fd_list, result, &error))
+ dex_promise_resolve_boolean (promise, TRUE);
else
dex_promise_reject (promise, error);
}
@@ -420,31 +420,26 @@ sysprof_user_sampler_prepare_fiber (gpointer user_data)
{
g_autoptr(DexPromise) promise = dex_promise_new ();
int event_fd_handle = g_unix_fd_list_append (fd_list, prepare->sampler->event_fd, NULL);
- g_autofd int fd = -1;
+ int capture_fd_handle = g_unix_fd_list_append (fd_list, prepare->sampler->capture_fd_write, NULL);
ipc_unwinder_call_unwind (unwinder,
prepare->stack_size,
g_variant_builder_end (&builder),
g_variant_new_handle (event_fd_handle),
+ g_variant_new_handle (capture_fd_handle),
fd_list,
NULL,
call_unwind_cb,
dex_ref (promise));
- fd = await_fd (dex_ref (promise), &error);
-
- if (fd == -1)
+ if (!dex_await (dex_ref (promise), &error))
{
_sysprof_recording_diagnostic (prepare->recording,
"Sampler",
- "Failed to setup user-space unwinder: %s",
+ "Failed to setup thread unwinder: %s",
error->message);
g_clear_error (&error);
}
- else
- {
- prepare->sampler->capture_fd = g_steal_fd (&fd);
- }
}
}
@@ -506,21 +501,26 @@ sysprof_user_sampler_record_fiber (gpointer user_data)
writer = _sysprof_recording_writer (record->recording);
- sysprof_user_sampler_ioctl (record->sampler, TRUE);
+ if (record->sampler->capture_fd_read != -1)
+ {
+ sysprof_user_sampler_ioctl (record->sampler, TRUE);
- g_debug ("Staring muxer for capture_fd");
- muxer_source = sysprof_muxer_source_new (g_steal_fd (&record->sampler->capture_fd), writer);
- g_source_set_static_name (muxer_source, "[stack-muxer]");
- g_source_attach (muxer_source, NULL);
+ g_debug ("Staring muxer for capture_fd %d", record->sampler->capture_fd_read);
+ muxer_source = sysprof_muxer_source_new (g_steal_fd (&record->sampler->capture_fd_read), writer);
+ g_source_set_static_name (muxer_source, "[stack-muxer]");
+ g_source_attach (muxer_source, NULL);
- if (!dex_await (dex_ref (record->cancellable), &error))
- g_debug ("UserSampler shutting down for reason: %s", error->message);
+ if (!dex_await (dex_ref (record->cancellable), &error))
+ g_debug ("UserSampler shutting down for reason: %s", error->message);
- write (record->sampler->event_fd, &exiting, sizeof exiting);
+ write (record->sampler->event_fd, &exiting, sizeof exiting);
- g_source_destroy (muxer_source);
+ g_source_destroy (muxer_source);
- sysprof_user_sampler_ioctl (record->sampler, FALSE);
+ sysprof_user_sampler_ioctl (record->sampler, FALSE);
+ }
+ else
+ g_warning ("No capture FD available for muxing");
return dex_future_new_for_boolean (TRUE);
}
@@ -555,7 +555,8 @@ sysprof_user_sampler_finalize (GObject *object)
g_clear_pointer (&self->perf_fds, g_array_unref);
- g_clear_fd (&self->capture_fd, NULL);
+ g_clear_fd (&self->capture_fd_read, NULL);
+ g_clear_fd (&self->capture_fd_write, NULL);
g_clear_fd (&self->event_fd, NULL);
G_OBJECT_CLASS (sysprof_user_sampler_parent_class)->finalize (object);
@@ -577,9 +578,19 @@ sysprof_user_sampler_class_init (SysprofUserSamplerClass *klass)
static void
sysprof_user_sampler_init (SysprofUserSampler *self)
{
- self->capture_fd = -1;
+ int fds[2];
+
self->event_fd = eventfd (0, EFD_CLOEXEC);
+ self->capture_fd_read = -1;
+ self->capture_fd_write = -1;
+
+ if (pipe2 (fds, O_CLOEXEC) == 0)
+ {
+ self->capture_fd_read = fds[0];
+ self->capture_fd_write = fds[1];
+ }
+
self->perf_fds = g_array_new (FALSE, FALSE, sizeof (int));
g_array_set_clear_func (self->perf_fds, close_fd);
}
diff --git a/src/sysprofd/ipc-unwinder-impl.c b/src/sysprofd/ipc-unwinder-impl.c
index 4341516b..e6a0d7ab 100644
--- a/src/sysprofd/ipc-unwinder-impl.c
+++ b/src/sysprofd/ipc-unwinder-impl.c
@@ -24,6 +24,7 @@
#include "config.h"
#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
#include <sys/prctl.h>
@@ -71,19 +72,16 @@ ipc_unwinder_impl_handle_unwind (IpcUnwinder *unwinder,
GUnixFDList *fd_list,
guint stack_size,
GVariant *arg_perf_fds,
- GVariant *arg_event_fd)
+ GVariant *arg_event_fd,
+ GVariant *arg_capture_fd)
{
g_autoptr(GSubprocessLauncher) launcher = NULL;
g_autoptr(GSubprocess) subprocess = NULL;
- g_autoptr(GUnixFDList) out_fd_list = NULL;
g_autoptr(GPtrArray) argv = NULL;
g_autoptr(GError) error = NULL;
- g_autofd int our_fd = -1;
- g_autofd int their_fd = -1;
+ g_autofd int capture_fd = -1;
g_autofd int event_fd = -1;
GVariantIter iter;
- int capture_fd_handle;
- int pair[2];
int next_target_fd = 3;
int perf_fd_handle;
int cpu;
@@ -116,13 +114,14 @@ ipc_unwinder_impl_handle_unwind (IpcUnwinder *unwinder,
g_ptr_array_add (argv, g_strdup (PACKAGE_LIBEXECDIR "/sysprof-live-unwinder"));
g_ptr_array_add (argv, g_strdup_printf ("--stack-size=%u", stack_size));
- if (-1 == (event_fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (arg_event_fd), &error)))
+ if (-1 == (event_fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (arg_event_fd), &error)) ||
+ -1 == (capture_fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (arg_capture_fd), &error)))
{
g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
return TRUE;
}
- g_ptr_array_add (argv, g_strdup_printf ("--event-fd=%u", next_target_fd));
+ g_ptr_array_add (argv, g_strdup_printf ("--event-fd=%d", next_target_fd));
g_subprocess_launcher_take_fd (launcher, g_steal_fd (&event_fd), next_target_fd++);
g_variant_iter_init (&iter, arg_perf_fds);
@@ -143,32 +142,8 @@ ipc_unwinder_impl_handle_unwind (IpcUnwinder *unwinder,
next_target_fd++);
}
- g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL);
-
- if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, pair) < 0)
- {
- int errsv = errno;
- g_dbus_method_invocation_return_error_literal (g_steal_pointer (&invocation),
- G_IO_ERROR,
- g_io_error_from_errno (errsv),
- g_strerror (errsv));
- return TRUE;
- }
-
- our_fd = g_steal_fd (&pair[0]);
- their_fd = g_steal_fd (&pair[1]);
-
- out_fd_list = g_unix_fd_list_new ();
- capture_fd_handle = g_unix_fd_list_append (out_fd_list, their_fd, &error);
-
- if (capture_fd_handle < 0)
- {
- g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
- return TRUE;
- }
-
g_ptr_array_add (argv, g_strdup_printf ("--capture-fd=%d", next_target_fd));
- g_subprocess_launcher_take_fd (launcher, g_steal_fd (&our_fd), next_target_fd++);
+ g_subprocess_launcher_take_fd (launcher, g_steal_fd (&capture_fd), next_target_fd++);
g_ptr_array_add (argv, NULL);
@@ -182,10 +157,7 @@ ipc_unwinder_impl_handle_unwind (IpcUnwinder *unwinder,
g_message ("sysprof-live-unwinder started as process %s",
g_subprocess_get_identifier (subprocess));
- ipc_unwinder_complete_unwind (unwinder,
- g_steal_pointer (&invocation),
- out_fd_list,
- g_variant_new_handle (capture_fd_handle));
+ ipc_unwinder_complete_unwind (unwinder, g_steal_pointer (&invocation), NULL);
g_subprocess_wait_check_async (subprocess,
NULL,
diff --git a/src/sysprofd/org.gnome.Sysprof3.Unwinder.xml b/src/sysprofd/org.gnome.Sysprof3.Unwinder.xml
index fb2c7848..86b3bdbe 100644
--- a/src/sysprofd/org.gnome.Sysprof3.Unwinder.xml
+++ b/src/sysprofd/org.gnome.Sysprof3.Unwinder.xml
@@ -17,7 +17,7 @@
<arg type="u" name="stack_size" direction="in"/>
<arg type="a(hi)" name="perf_fds" direction="in"/>
<arg type="h" name="event_fd" direction="in"/>
- <arg type="h" name="capture_fd" direction="out"/>
+ <arg type="h" name="capture_fd" direction="in"/>
</method>
</interface>
</node>
--
2.45.2

View File

@ -0,0 +1,31 @@
From 6cdafd91ef71b15af66107b37a5db6b5a3dcd319 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 15:41:33 -0800
Subject: [PATCH 28/31] sysprof-live-unwinder: error out on capture failure
---
src/sysprof-live-unwinder/main.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/sysprof-live-unwinder/main.c b/src/sysprof-live-unwinder/main.c
index e14eaf6c..a1cd53fa 100644
--- a/src/sysprof-live-unwinder/main.c
+++ b/src/sysprof-live-unwinder/main.c
@@ -708,7 +708,13 @@ Examples:\n\
return EXIT_FAILURE;
}
- writer = sysprof_capture_writer_new_from_fd (g_steal_fd (&capture_fd), CAPTURE_BUFFER_SIZE);
+ if (!(writer = sysprof_capture_writer_new_from_fd (g_steal_fd (&capture_fd), CAPTURE_BUFFER_SIZE)))
+ {
+ int errsv = errno;
+ g_printerr ("Failed to create capture writer: %s\n",
+ g_strerror (errsv));
+ return EXIT_FAILURE;
+ }
if (all_perf_fds->len == 0)
{
--
2.45.2

View File

@ -0,0 +1,37 @@
From d2d0467c28a4c2b9288cec5cfa83c42ec94c533f Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 15:53:12 -0800
Subject: [PATCH 29/31] sysprofd: remove unused code
---
src/sysprofd/ipc-unwinder-impl.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/src/sysprofd/ipc-unwinder-impl.c b/src/sysprofd/ipc-unwinder-impl.c
index e6a0d7ab..2290377b 100644
--- a/src/sysprofd/ipc-unwinder-impl.c
+++ b/src/sysprofd/ipc-unwinder-impl.c
@@ -27,7 +27,6 @@
#include <fcntl.h>
#include <signal.h>
-#include <sys/prctl.h>
#include <sys/socket.h>
#include <glib/gstdio.h>
@@ -41,12 +40,6 @@ struct _IpcUnwinderImpl
IpcUnwinderSkeleton parent_instance;
};
-static void
-child_setup (gpointer data)
-{
- prctl (PR_SET_PDEATHSIG, SIGKILL);
-}
-
static void
ipc_unwinder_impl_wait_cb (GObject *object,
GAsyncResult *result,
--
2.45.2

View File

@ -0,0 +1,26 @@
From 2ab855d5fdfd70948e6deeef3cfafb759d1c91f7 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 15:54:12 -0800
Subject: [PATCH 30/31] build: lower libpanel requirement to ease some build
systems
---
src/sysprof/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build
index ab6a701a..62f3441f 100644
--- a/src/sysprof/meson.build
+++ b/src/sysprof/meson.build
@@ -88,7 +88,7 @@ sysprof_deps = [
cc.find_library('m', required: false),
dependency('gtk4', version: gtk_req_version),
dependency('libadwaita-1', version: '>= 1.6.0'),
- dependency('libpanel-1', version: '>= 1.7.0'),
+ dependency('libpanel-1', version: '>= 1.4'),
libsysprof_static_dep,
]
--
2.45.2

View File

@ -0,0 +1,168 @@
From d34689ff54650a581a2af3595a6f42c7d5c0166e Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 16:20:06 -0800
Subject: [PATCH 31/31] build: allow await for FD with older libdex
This just makes backports easier.
---
meson.build | 2 +-
src/libsysprof/sysprof-fd-private.h | 7 +++++
src/libsysprof/sysprof-fd.c | 24 ++++++++++++++++
src/libsysprof/sysprof-user-sampler.c | 28 ++-----------------
.../tests/test-live-unwinder.c | 5 ++--
5 files changed, 37 insertions(+), 29 deletions(-)
diff --git a/meson.build b/meson.build
index 16d64e8a..e2a9a995 100644
--- a/meson.build
+++ b/meson.build
@@ -45,7 +45,7 @@ need_libsysprof = (need_gtk or
get_option('tools') or
get_option('tests'))
-dex_req = '0.9'
+dex_req = '0.8'
glib_req = '2.76.0'
gtk_req = '4.15'
polkit_req = '0.105'
diff --git a/src/libsysprof/sysprof-fd-private.h b/src/libsysprof/sysprof-fd-private.h
index 1d4dfabc..f6f11b0c 100644
--- a/src/libsysprof/sysprof-fd-private.h
+++ b/src/libsysprof/sysprof-fd-private.h
@@ -22,6 +22,8 @@
#include <glib-object.h>
+#include <libdex.h>
+
G_BEGIN_DECLS
#define SYSPROF_TYPE_FD (sysprof_fd_get_type())
@@ -36,4 +38,9 @@ void sysprof_fd_free (SysprofFD *fd);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofFD, sysprof_fd_free)
+int sysprof_await_fd (DexFuture *future,
+ GError **error);
+void sysprof_promise_resolve_fd (DexPromise *promise,
+ int fd);
+
G_END_DECLS
diff --git a/src/libsysprof/sysprof-fd.c b/src/libsysprof/sysprof-fd.c
index 5e34f8d9..a571cefe 100644
--- a/src/libsysprof/sysprof-fd.c
+++ b/src/libsysprof/sysprof-fd.c
@@ -65,3 +65,27 @@ sysprof_fd_dup (const SysprofFD *fd)
}
G_DEFINE_BOXED_TYPE (SysprofFD, sysprof_fd, sysprof_fd_dup, sysprof_fd_free)
+
+void
+sysprof_promise_resolve_fd (DexPromise *promise,
+ int fd)
+{
+ GValue gvalue = {SYSPROF_TYPE_FD, {{.v_pointer = &fd}, {.v_int = 0}}};
+ dex_promise_resolve (promise, &gvalue);
+}
+
+int
+sysprof_await_fd (DexFuture *future,
+ GError **error)
+{
+ SysprofFD *fd = dex_await_boxed (future, error);
+ int ret = -1;
+
+ if (fd != NULL)
+ {
+ ret = sysprof_fd_steal (fd);
+ sysprof_fd_free (fd);
+ }
+
+ return ret;
+}
diff --git a/src/libsysprof/sysprof-user-sampler.c b/src/libsysprof/sysprof-user-sampler.c
index 6079708e..05f97cbf 100644
--- a/src/libsysprof/sysprof-user-sampler.c
+++ b/src/libsysprof/sysprof-user-sampler.c
@@ -89,30 +89,6 @@ close_fd (gpointer data)
}
}
-static void
-promise_resolve_fd (DexPromise *promise,
- int fd)
-{
- GValue gvalue = {SYSPROF_TYPE_FD, {{.v_pointer = &fd}, {.v_int = 0}}};
- dex_promise_resolve (promise, &gvalue);
-}
-
-static int
-await_fd (DexFuture *future,
- GError **error)
-{
- SysprofFD *fd = dex_await_boxed (future, error);
- int ret = -1;
-
- if (fd != NULL)
- {
- ret = sysprof_fd_steal (fd);
- sysprof_fd_free (fd);
- }
-
- return ret;
-}
-
static void
sysprof_user_sampler_ioctl (SysprofUserSampler *self,
gboolean enable)
@@ -177,7 +153,7 @@ _perf_event_open_cb (GObject *object,
if (-1 == (fd = g_unix_fd_list_get (fd_list, handle, &error)))
goto failure;
- promise_resolve_fd (promise, g_steal_fd (&fd));
+ sysprof_promise_resolve_fd (promise, g_steal_fd (&fd));
return;
}
@@ -262,7 +238,7 @@ try_again:
_perf_event_open_cb,
dex_ref (promise));
- if (-1 == (perf_fd = await_fd (dex_ref (promise), error)))
+ if (-1 == (perf_fd = sysprof_await_fd (dex_ref (promise), error)))
{
g_clear_pointer (&options, g_variant_unref);
diff --git a/src/sysprof-live-unwinder/tests/test-live-unwinder.c b/src/sysprof-live-unwinder/tests/test-live-unwinder.c
index 114cc568..c3eda85a 100644
--- a/src/sysprof-live-unwinder/tests/test-live-unwinder.c
+++ b/src/sysprof-live-unwinder/tests/test-live-unwinder.c
@@ -33,6 +33,7 @@
#include <sysprof.h>
+#include "sysprof-fd-private.h"
#include "sysprof-perf-event-stream-private.h"
#if HAVE_POLKIT_AGENT
@@ -89,7 +90,7 @@ open_perf_stream_cb (GObject *object,
if (-1 != (fd = g_unix_fd_list_get (fd_list, handle, &error)))
{
- dex_promise_resolve_fd (promise, g_steal_fd (&fd));
+ sysprof_promise_resolve_fd (promise, g_steal_fd (&fd));
return;
}
}
@@ -179,7 +180,7 @@ try_again:
open_perf_stream_cb,
dex_ref (promise));
- fd = dex_await_fd (dex_ref (promise), error);
+ fd = sysprof_await_fd (dex_ref (promise), error);
if (*error == NULL)
{
--
2.45.2

View File

@ -0,0 +1,37 @@
From 99f807240e4be653a122b9e443cd38782962bc59 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 6 Nov 2024 13:09:31 -0800
Subject: [PATCH] sysprof: default stack-capturing as enabled
This is for CentOS/RHEL only as other distributions have frame-pointers.
---
src/sysprof/sysprof-recording-template.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/sysprof/sysprof-recording-template.c b/src/sysprof/sysprof-recording-template.c
index ee4d4f01..b3018763 100644
--- a/src/sysprof/sysprof-recording-template.c
+++ b/src/sysprof/sysprof-recording-template.c
@@ -446,7 +446,8 @@ sysprof_recording_template_class_init (SysprofRecordingTemplateClass *klass)
properties[PROP_USER_STACKS] =
g_param_spec_boolean ("user-stacks", NULL, NULL,
- FALSE,
+ /* Default to stack capturing in CentOS/RHEL */
+ TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties[PROP_STACK_SIZE] =
@@ -473,6 +474,9 @@ sysprof_recording_template_init (SysprofRecordingTemplate *self)
self->command_line = g_strdup ("");
self->cwd = g_strdup("");
self->stack_size = DEFAULT_STACK_SIZE;
+
+ /* Default to stack capturing in CentOS/RHEL */
+ self->user_stacks = TRUE;
}
SysprofRecordingTemplate *
--
2.45.2

View File

@ -0,0 +1,29 @@
From 08d94d9b982e5d4a6e7a67b45ae71bd51ca3fe0d Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Wed, 13 Nov 2024 17:16:44 -0800
Subject: [PATCH] tests: fix test on s390
---
src/sysprof-live-unwinder/tests/test-live-unwinder.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/sysprof-live-unwinder/tests/test-live-unwinder.c b/src/sysprof-live-unwinder/tests/test-live-unwinder.c
index c3eda85a..a0dabeb3 100644
--- a/src/sysprof-live-unwinder/tests/test-live-unwinder.c
+++ b/src/sysprof-live-unwinder/tests/test-live-unwinder.c
@@ -59,7 +59,11 @@
#define SYSPROF_ARCH_PREFERRED_REGS DWARF_NEEDED_REGS
/* TODO: add other architectures, imitating the linux tools/perf tree */
#else
-# define SYSPROF_ARCH_PREFERRED_REGS PERF_REG_EXTENDED_MASK
+# ifdef PERF_REG_EXTENDED_MASK
+# define SYSPROF_ARCH_PREFERRED_REGS PERF_REG_EXTENDED_MASK
+# else
+# define SYSPROF_ARCH_PREFERRED_REGS 0
+# endif
#endif /* _ASM_{arch}_PERF_REGS_H */
static gboolean sample_stack;
--
2.45.2

View File

@ -1,466 +0,0 @@
%global glib2_version 2.67.4
Name: sysprof
Version: 3.40.1
Release: 3%{?dist}
Summary: A system-wide Linux profiler
License: GPLv3+
URL: http://www.sysprof.com
Source0: https://download.gnome.org/sources/sysprof/3.40/sysprof-%{version}.tar.xz
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: gettext
BuildRequires: itstool
BuildRequires: meson
BuildRequires: pkgconfig(gio-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(gio-unix-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(gobject-2.0)
BuildRequires: pkgconfig(gtk+-3.0)
BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(libdazzle-1.0)
BuildRequires: pkgconfig(libsystemd)
BuildRequires: pkgconfig(polkit-gobject-1)
BuildRequires: pkgconfig(systemd)
BuildRequires: /usr/bin/appstream-util
BuildRequires: /usr/bin/desktop-file-validate
Requires: glib2%{?_isa} >= %{glib2_version}
Requires: hicolor-icon-theme
Requires: %{name}-cli%{?_isa} = %{version}-%{release}
Requires: libsysprof-ui%{?_isa} = %{version}-%{release}
%description
Sysprof is a sampling CPU profiler for Linux that collects accurate,
high-precision data and provides efficient access to the sampled
calltrees.
%package cli
Summary: Sysprof command line utility
# sysprofd needs turbostat
Requires: kernel-tools
Requires: libsysprof%{?_isa} = %{version}-%{release}
%description cli
The %{name}-cli package contains the sysprof-cli command line utility.
%package -n libsysprof
Summary: Sysprof libraries
%description -n libsysprof
The libsysprof package contains the Sysprof libraries.
%package -n libsysprof-ui
Summary: Sysprof UI library
%description -n libsysprof-ui
The libsysprof-ui package contains the Sysprof UI library.
%package capture-devel
Summary: Development files for sysprof-capture static library
License: BSD-2-Clause-Patent
Provides: sysprof-capture-static = %{version}-%{release}
# Split out in F34
Conflicts: %{name}-devel < 3.39.94-1
%description capture-devel
The %{name}-capture-devel package contains the sysprof-capture static library and header files.
%package devel
Summary: Development files for %{name}
Requires: %{name}-capture-devel%{?_isa} = %{version}-%{release}
Requires: libsysprof%{?_isa} = %{version}-%{release}
Requires: libsysprof-ui%{?_isa} = %{version}-%{release}
%description devel
The %{name}-devel package contains libraries and header files for
developing applications that use %{name}.
%prep
%autosetup -p1
%build
%meson
%meson_build
%install
%meson_install
%find_lang %{name} --with-gnome
%check
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/*.appdata.xml
desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop
%files
%license COPYING
%doc NEWS README.md AUTHORS
%{_bindir}/sysprof
%{_datadir}/applications/org.gnome.Sysprof3.desktop
%{_datadir}/glib-2.0/schemas/org.gnome.sysprof3.gschema.xml
%{_datadir}/icons/hicolor/*/*/*
%{_datadir}/metainfo/org.gnome.Sysprof3.appdata.xml
%{_datadir}/mime/packages/sysprof-mime.xml
%files cli -f %{name}.lang
%license COPYING
%{_bindir}/sysprof-cli
%{_libexecdir}/sysprofd
%{_datadir}/dbus-1/system.d/org.gnome.Sysprof2.conf
%{_datadir}/dbus-1/system.d/org.gnome.Sysprof3.conf
%{_datadir}/dbus-1/system-services/org.gnome.Sysprof2.service
%{_datadir}/dbus-1/system-services/org.gnome.Sysprof3.service
%{_datadir}/polkit-1/actions/org.gnome.sysprof3.policy
%{_unitdir}/sysprof2.service
%{_unitdir}/sysprof3.service
%files -n libsysprof
%license COPYING
%{_libdir}/libsysprof-4.so
%{_libdir}/libsysprof-memory-4.so
%{_libdir}/libsysprof-speedtrack-4.so
%files -n libsysprof-ui
%license COPYING
%{_libdir}/libsysprof-ui-4.so
%files capture-devel
%license src/libsysprof-capture/COPYING
%dir %{_includedir}/sysprof-4
%{_includedir}/sysprof-4/sysprof-address.h
%{_includedir}/sysprof-4/sysprof-capture-condition.h
%{_includedir}/sysprof-4/sysprof-capture-cursor.h
%{_includedir}/sysprof-4/sysprof-capture.h
%{_includedir}/sysprof-4/sysprof-capture-reader.h
%{_includedir}/sysprof-4/sysprof-capture-types.h
%{_includedir}/sysprof-4/sysprof-capture-writer.h
%{_includedir}/sysprof-4/sysprof-clock.h
%{_includedir}/sysprof-4/sysprof-collector.h
%{_includedir}/sysprof-4/sysprof-macros.h
%{_includedir}/sysprof-4/sysprof-platform.h
%{_includedir}/sysprof-4/sysprof-version.h
%{_includedir}/sysprof-4/sysprof-version-macros.h
%{_libdir}/libsysprof-capture-4.a
%{_libdir}/pkgconfig/sysprof-capture-4.pc
%files devel
%{_includedir}/sysprof-4/
%{_libdir}/pkgconfig/sysprof-4.pc
%{_libdir}/pkgconfig/sysprof-ui-4.pc
%{_datadir}/dbus-1/interfaces/org.gnome.Sysprof2.xml
%{_datadir}/dbus-1/interfaces/org.gnome.Sysprof3.Profiler.xml
%{_datadir}/dbus-1/interfaces/org.gnome.Sysprof3.Service.xml
%changelog
* Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 3.40.1-3
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 3.40.1-2
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Tue Mar 23 2021 Kalev Lember <klember@redhat.com> - 3.40.1-1
- Update to 3.40.1
* Mon Mar 22 2021 Kalev Lember <klember@redhat.com> - 3.40.0-1
- Update to 3.40.0
* Tue Mar 16 2021 Kalev Lember <klember@redhat.com> - 3.39.94-2
- Add explicit conflicts to help with upgrades
* Thu Feb 25 2021 Kalev Lember <klember@redhat.com> - 3.39.94-1
- Update to 3.39.94
* Wed Feb 24 2021 Kalev Lember <klember@redhat.com> - 3.39.92-2
- Split sysprof-capture library and header files out to sysprof-capture-devel
- Update minimum required glib2 version
* Wed Feb 24 2021 Kalev Lember <klember@redhat.com> - 3.39.92-1
- Update to 3.39.92
* Mon Feb 22 2021 Kalev Lember <klember@redhat.com> - 3.39.90-2
- Specify pic for static libsysprof-capture
* Thu Feb 18 2021 Kalev Lember <klember@redhat.com> - 3.39.90-1
- Update to 3.39.90
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 3.38.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Tue Oct 20 2020 Kalev Lember <klember@redhat.com> - 3.38.1-2
- Rebuild
* Fri Oct 16 2020 Kalev Lember <klember@redhat.com> - 3.38.1-1
- Update to 3.38.1
* Sun Sep 20 2020 Kalev Lember <klember@redhat.com> - 3.38.0-2
- Split out a separate libsysprof package and avoid -devel subpackage depending
on the GUI app
* Sat Sep 12 2020 Kalev Lember <klember@redhat.com> - 3.38.0-1
- Update to 3.38.0
* Mon Sep 07 2020 Kalev Lember <klember@redhat.com> - 3.37.92-1
- Update to 3.37.92
* Mon Aug 17 2020 Kalev Lember <klember@redhat.com> - 3.37.90-1
- Update to 3.37.90
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.36.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Sat Mar 07 2020 Kalev Lember <klember@redhat.com> - 3.36.0-1
- Update to 3.36.0
* Mon Mar 02 2020 Kalev Lember <klember@redhat.com> - 3.35.92-1
- Update to 3.35.92
* Fri Jan 31 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.35.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Fri Jan 10 2020 Kalev Lember <klember@redhat.com> - 3.35.3-1
- Update to 3.35.3
* Wed Dec 11 2019 Adam Williamson <awilliam@redhat.com> - 3.35.2-1
- Update to 3.35.2
* Mon Oct 07 2019 Kalev Lember <klember@redhat.com> - 3.34.1-1
- Update to 3.34.1
* Tue Sep 10 2019 Kalev Lember <klember@redhat.com> - 3.34.0-1
- Update to 3.34.0
* Thu Sep 05 2019 Kalev Lember <klember@redhat.com> - 3.33.92-1
- Update to 3.33.92
- Set minimum required glib2 version
* Tue Aug 27 2019 Kalev Lember <klember@redhat.com> - 3.33.90-2
- Add kernel-tools runtime dep for turbostat
* Mon Aug 26 2019 Kalev Lember <klember@redhat.com> - 3.33.90-1
- Update to 3.33.90
* Sat Jul 27 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.33.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Fri Jul 19 2019 Kalev Lember <klember@redhat.com> - 3.33.3-1
- Update to 3.33.3
* Wed Mar 13 2019 Kalev Lember <klember@redhat.com> - 3.32.0-1
- Update to 3.32.0
* Tue Feb 19 2019 Kalev Lember <klember@redhat.com> - 3.31.91-1
- Update to 3.31.91
* Thu Feb 07 2019 Kalev Lember <klember@redhat.com> - 3.31.90-1
- Update to 3.31.90
* Sun Feb 03 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.31.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Thu Jan 10 2019 Kalev Lember <klember@redhat.com> - 3.31.1-2
- Backport new API for gnome-builder
* Tue Oct 09 2018 Kalev Lember <klember@redhat.com> - 3.31.1-1
- Update to 3.31.1
* Wed Sep 26 2018 Kalev Lember <klember@redhat.com> - 3.30.1-1
- Update to 3.30.1
* Fri Sep 07 2018 Kalev Lember <klember@redhat.com> - 3.30.0-1
- Update to 3.30.0
- Drop ldconfig scriptlets
* Tue Jul 31 2018 Florian Weimer <fweimer@redhat.com> - 3.28.1-3
- Rebuild with fixed binutils
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.28.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Tue Apr 10 2018 Kalev Lember <klember@redhat.com> - 3.28.1-1
- Update to 3.28.1
* Wed Mar 14 2018 Kalev Lember <klember@redhat.com> - 3.28.0-1
- Update to 3.28.0
* Mon Mar 05 2018 Kalev Lember <klember@redhat.com> - 3.27.92-1
- Update to 3.27.92
* Sat Mar 03 2018 Kalev Lember <klember@redhat.com> - 3.27.91-1
- Update to 3.27.91
- Switch to the meson build system
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.26.1-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Sat Feb 03 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3.26.1-3
- Switch to %%ldconfig_scriptlets
* Fri Jan 05 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3.26.1-2
- Remove obsolete scriptlets
* Sun Oct 08 2017 Kalev Lember <klember@redhat.com> - 3.26.1-1
- Update to 3.26.1
* Sat Sep 16 2017 Kalev Lember <klember@redhat.com> - 3.26.0-1
- Update to 3.26.0
* Thu Sep 07 2017 Kalev Lember <klember@redhat.com> - 3.25.92-1
- Update to 3.25.92
* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.24.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.24.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Tue Apr 11 2017 Kalev Lember <klember@redhat.com> - 3.24.1-1
- Update to 3.24.1
* Mon Mar 20 2017 Kalev Lember <klember@redhat.com> - 3.24.0-1
- Update to 3.24.0
* Thu Mar 16 2017 Kalev Lember <klember@redhat.com> - 3.23.92-1
- Update to 3.23.92
* Wed Mar 01 2017 Kalev Lember <klember@redhat.com> - 3.23.91-1
- Update to 3.23.91
- Add appdata validation
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.22.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Tue Nov 29 2016 Kalev Lember <klember@redhat.com> - 3.22.3-1
- Update to 3.22.3
* Wed Nov 02 2016 Kalev Lember <klember@redhat.com> - 3.22.2-1
- Update to 3.22.2
* Wed Oct 12 2016 Kalev Lember <klember@redhat.com> - 3.22.1-1
- Update to 3.22.1
- Don't use -Werror for builds
* Wed Sep 21 2016 Kalev Lember <klember@redhat.com> - 3.22.0-2
- Split out sysprof-cli and libsysprof-ui subpackages
* Wed Sep 21 2016 Kalev Lember <klember@redhat.com> - 3.22.0-1
- Update to 3.22.0
* Mon Sep 5 2016 Peter Robinson <pbrobinson@fedoraproject.org> 3.21.91-2
- Build on all arches now generic atomics supported
* Fri Sep 02 2016 Kalev Lember <klember@redhat.com> - 3.21.91-1
- Update to 3.21.91
* Tue Aug 23 2016 Kalev Lember <klember@redhat.com> - 3.21.90-2
- Enable building for arm architectures
* Tue Aug 23 2016 Kalev Lember <klember@redhat.com> - 3.21.90-1
- Update to 3.21.90
* Mon Aug 08 2016 Kalev Lember <klember@redhat.com> - 3.20.0-1
- Update to 3.20.0
- Modernize spec file
* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 1.2.0-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Fri Jun 19 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Mon Aug 18 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
* Sun Aug 04 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
* Fri Jun 28 2013 Gianluca Sforna <giallu@gmail.com> 1.2.0-3
- fix udev rule path (#979545)
* Fri Feb 15 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
* Sat Sep 15 2012 Gianluca Sforna <giallu@gmail.com> 1.2.0-1
- New upstream release
* Sat Jul 21 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.8-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.8-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
* Mon Nov 07 2011 Adam Jackson <ajax@redhat.com> 1.1.8-2
- Rebuild to break bogus libpng dependency
* Thu Jul 28 2011 Gianluca Sforna <giallu@gmail.com> 1.1.8-1
- New upstream release
* Fri Jun 24 2011 Gianluca Sforna <giallu@gmail.com> 1.1.6-3
- Fix missing icon (#558089)
* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.6-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Tue Jun 8 2010 Gianluca Sforna <giallu gmail com> - 1.1.6-1
- New upstream release
* Sun Sep 27 2009 Gianluca Sforna <giallu gmail com> - 1.1.2-3
- Incorporate suggestions from package review
- Require kernel 2.6.31
- Updated description
* Sat Sep 26 2009 Gianluca Sforna <giallu gmail com> - 1.1.2-1
- New upstream release
* Wed Apr 9 2008 Gianluca Sforna <giallu gmail com> - 1.0.9-1
- version update to 1.0.9
* Tue Aug 28 2007 Gianluca Sforna <giallu gmail com> 1.0.8-2
- update License field
* Thu Dec 21 2006 Gianluca Sforna <giallu gmail com> 1.0.8-1
- version update to 1.0.8
* Tue Nov 21 2006 Gianluca Sforna <giallu gmail com> 1.0.7-1
- version update to 1.0.7
* Wed Nov 1 2006 Gianluca Sforna <giallu gmail com> 1.0.5-1
- version update
* Sun Oct 8 2006 Gianluca Sforna <giallu gmail com> 1.0.3-6
- better to use ExclusiveArch %%{ix86} (thanks Ville)
* Thu Oct 5 2006 Gianluca Sforna <giallu gmail com> 1.0.3-5
- add ExclusiveArch to match sysprof-kmod supported archs
* Mon Oct 2 2006 Gianluca Sforna <giallu gmail com> 1.0.3-4
- add .desktop file
* Sat Sep 30 2006 Gianluca Sforna <giallu gmail com> 1.0.3-3
- versioned Provides
- add BR: binutils-devel
* Fri Sep 29 2006 Gianluca Sforna <giallu gmail com> 1.0.3-2
- own sysprof directory
* Thu Jun 22 2006 Gianluca Sforna <giallu gmail com> 1.0.3-1
- version update
- use standard %%configure macro
* Sun May 14 2006 Gianluca Sforna <giallu gmail com> 1.0.2-1
- Initial Version

6
gating.yaml Normal file
View File

@ -0,0 +1,6 @@
--- !Policy
product_versions:
- rhel-10
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: desktop-qe.desktop-ci.tier1-gating.functional}

2
sources Normal file
View File

@ -0,0 +1,2 @@
SHA512 (sysprof-47.1.tar.xz) = 9f8db2169c761109f27fe45f805f863b6f15f35cc7ad8ccaf68f047446dc8552c27a340442a1466f719b588045573f9a9c0e4fa1ea15f33f12074ca64a074e7c
SHA512 (libunwind-1.8.1.tar.gz) = aba7b578c1b8cbe78f05b64e154f3530525f8a34668b2a9f1ee6acb4b22c857befe34ad4e9e8cca99dbb66689d41bc72060a8f191bd8be232725d342809431b3

254
sysprof.spec Normal file
View File

@ -0,0 +1,254 @@
%global glib2_version 2.76.0
%global tarball_version %%(echo %{version} | tr '~' '.')
%global bundled_libunwind %{defined rhel}
%if 0%{?bundled_libunwind}
%global libunwind_version 1.8.1
%global _legacy_common_support 1
%endif
Name: sysprof
Version: 47.1
Release: %autorelease
Summary: A system-wide Linux profiler
License: GPL-2.0-or-later AND GPL-3.0-or-later AND CC-BY-SA-4.0 AND BSD-2-Clause-Patent
URL: http://www.sysprof.com
Source0: https://download.gnome.org/sources/sysprof/47/sysprof-%{tarball_version}.tar.xz
%if 0%{?bundled_libunwind}
Source1: https://github.com/libunwind/libunwind/releases/download/v%{libunwind_version}/libunwind-%{libunwind_version}.tar.gz
%endif
# Backports of debuginfod and sysprof-live-unwinder from GNOME 48
Patch: 0001-build-add-47-version-macros.patch
Patch: 0002-libsysprof-elf-do-not-allow-setting-self-as-debug-li.patch
Patch: 0003-libsysprof-elf-do-not-generate-fallback-names.patch
Patch: 0004-sysprof-update-to-AdwSpinner.patch
Patch: 0005-sysprof-add-SysprofDocumentTask-abstraction.patch
Patch: 0006-libsysprof-add-setup-hooks-for-symbolizers.patch
Patch: 0007-libsysprof-hoist-fallback-symbol-creation.patch
Patch: 0008-libsysprof-add-debuginfod-symbolizer.patch
Patch: 0009-libsysprof-ensure-access-to-process-info.patch
Patch: 0010-libsysprof-fix-building-with-Ddebuginfod-auto.patch
Patch: 0011-libsysprof-return-NULL-instance-unless-debuginfod-wo.patch
Patch: 0012-build-always-build-debuginfod-symbolizer.patch
Patch: 0013-libsysprof-remove-unnecessary-address-calculation.patch
Patch: 0014-libsysprof-add-muxer-GSource.patch
Patch: 0015-libsysprof-add-support-for-stack-regs-options-in-att.patch
Patch: 0016-sysprofd-add-support-for-unwinding-without-frame-poi.patch
Patch: 0017-libsysprof-add-SysprofUserSampler-for-live-unwinding.patch
Patch: 0018-sysprof-cli-add-support-for-live-unwinding.patch
Patch: 0019-sysprof-add-UI-for-live-unwinding.patch
Patch: 0020-sysprof-live-unwinder-ifdef-unused-code-off-x86.patch
Patch: 0021-sysprof-only-show-user-stack-sampling-on-x86.patch
Patch: 0022-libsysprof-check-for-PERF_REG_EXTENDED_MASK-availabi.patch
Patch: 0023-sysprof-live-unwinder-fix-source-func-prototype.patch
Patch: 0024-sysprof-live-unwinder-handle-large-stack-unwind-size.patch
Patch: 0025-unwinder-wait-for-completion-of-subprocess.patch
Patch: 0026-sysprof-user-sampler-implement-await-for-FDs.patch
Patch: 0027-libsysprof-provide-unwind-pipe-from-client.patch
Patch: 0028-sysprof-live-unwinder-error-out-on-capture-failure.patch
Patch: 0029-sysprofd-remove-unused-code.patch
Patch: 0030-build-lower-libpanel-requirement-to-ease-some-build-.patch
Patch: 0031-build-allow-await-for-FD-with-older-libdex.patch
Patch: 0032-sysprof-default-stack-capturing-as-enabled.patch
Patch: 0033-tests-fix-test-on-s390.patch
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: gettext
BuildRequires: itstool
BuildRequires: meson
BuildRequires: pkgconfig(gio-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(gio-unix-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(gobject-2.0)
BuildRequires: pkgconfig(gtk4)
BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(libadwaita-1)
BuildRequires: pkgconfig(libdex-1)
BuildRequires: pkgconfig(libpanel-1)
BuildRequires: pkgconfig(libsystemd)
BuildRequires: pkgconfig(polkit-gobject-1)
BuildRequires: pkgconfig(systemd)
BuildRequires: pkgconfig(libdw)
BuildRequires: pkgconfig(libdebuginfod)
BuildRequires: /usr/bin/appstream-util
BuildRequires: /usr/bin/desktop-file-validate
%if 0%{?bundled_libunwind}
BuildRequires: automake libtool autoconf make
%else
BuildRequires: pkgconfig(libunwind-generic)
%endif
Requires: glib2%{?_isa} >= %{glib2_version}
Requires: hicolor-icon-theme
Requires: %{name}-cli%{?_isa} = %{version}-%{release}
%description
Sysprof is a sampling CPU profiler for Linux that collects accurate,
high-precision data and provides efficient access to the sampled
calltrees.
%package agent
Summary: Sysprof agent utility
%description agent
The %{name}-agent package contains the sysprof-agent program. It provides a P2P
D-Bus API to the process which can control subprocesses. It's used by IDE
tooling to have more control across container boundaries.
%package cli
Summary: Sysprof command line utility
# sysprofd needs turbostat
Requires: kernel-tools
Requires: libsysprof%{?_isa} = %{version}-%{release}
%description cli
The %{name}-cli package contains the sysprof-cli command line utility.
%package -n libsysprof
Summary: Sysprof libraries
# Subpackage removed/obsoleted in F39
Obsoletes: libsysprof-ui < 45.0
%if 0%{?bundled_libunwind}
Provides: bundled(libunwind) = %{libunwind_version}
%endif
%description -n libsysprof
The libsysprof package contains the Sysprof libraries.
%package capture-devel
Summary: Development files for sysprof-capture static library
License: BSD-2-Clause-Patent
Provides: sysprof-capture-static = %{version}-%{release}
%description capture-devel
The %{name}-capture-devel package contains the sysprof-capture static library and header files.
%package devel
Summary: Development files for %{name}
Requires: %{name}-capture-devel%{?_isa} = %{version}-%{release}
Requires: libsysprof%{?_isa} = %{version}-%{release}
%description devel
The %{name}-devel package contains libraries and header files for
developing applications that use %{name}.
%prep
%if 0%{?bundled_libunwind}
%setup -b 1 -n libunwind-%{libunwind_version}
%endif
%setup -n sysprof-%{tarball_version}
%autopatch -p1
%build
%if 0%{?bundled_libunwind}
# First build private libunwind
%global libunwind_install_dir %{buildroot}%{_builddir}/libunwind
pushd ../libunwind-%{libunwind_version}
mkdir -p %{_builddir}/libunwind/
aclocal
libtoolize --force
autoheader
automake --add-missing
autoconf
%configure --enable-static --disable-shared --enable-setjmp=no --disable-debug --disable-documentation --disable-ptrace --disable-coredump --disable-minidebuginfo --disable-zlibdebuginfo --with-pic
make %{?_smp_mflags} install DESTDIR=%{libunwind_install_dir}
popd
# Our "/usr" install to DESTDIR wont get picked up by the
# pkgconfig use in meson so ensure access to those include
# and linker directories manually.
export CFLAGS="$CFLAGS -I%{libunwind_install_dir}/usr/include"
export LDFLAGS="$LDFLAGS -L%{libunwind_install_dir}/usr/%{_lib}"
%global pkg_config_path_override --pkg-config-path %{libunwind_install_dir}/usr/%{_lib}/pkgconfig
%endif
# Now build sysprof
%meson %{?pkg_config_path_override}
%meson_build
%install
%meson_install
%find_lang %{name} --with-gnome
%if 0%{?bundled_libunwind}
# Appease checks which would include buildroot paths for the
# libunwind-generic.a linked in.
strip -s %{buildroot}/usr/%{_lib}/libsysprof-*.so
%endif
%check
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/*.appdata.xml
desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop
%files
%license COPYING
%doc NEWS README.md AUTHORS
%{_bindir}/sysprof
%{_datadir}/applications/org.gnome.Sysprof.desktop
%{_datadir}/icons/hicolor/*/*/*
%{_datadir}/metainfo/org.gnome.Sysprof.appdata.xml
%{_datadir}/mime/packages/sysprof-mime.xml
%files agent
%license COPYING
%{_bindir}/sysprof-agent
%files cli -f %{name}.lang
%license COPYING
%{_bindir}/sysprof-cli
%{_libexecdir}/sysprofd
%{_libexecdir}/sysprof-live-unwinder
%{_datadir}/dbus-1/system.d/org.gnome.Sysprof3.conf
%{_datadir}/dbus-1/system-services/org.gnome.Sysprof3.service
%{_datadir}/polkit-1/actions/org.gnome.sysprof3.policy
%{_unitdir}/sysprof3.service
%files -n libsysprof
%license COPYING COPYING.gpl-2
%{_libdir}/libsysprof-6.so.6*
%{_libdir}/libsysprof-memory-6.so
%{_libdir}/libsysprof-speedtrack-6.so
%{_libdir}/libsysprof-tracer-6.so
%files capture-devel
%license src/libsysprof-capture/COPYING
%dir %{_includedir}/sysprof-6
%{_includedir}/sysprof-6/sysprof-address.h
%{_includedir}/sysprof-6/sysprof-capture-condition.h
%{_includedir}/sysprof-6/sysprof-capture-cursor.h
%{_includedir}/sysprof-6/sysprof-capture.h
%{_includedir}/sysprof-6/sysprof-capture-reader.h
%{_includedir}/sysprof-6/sysprof-capture-types.h
%{_includedir}/sysprof-6/sysprof-capture-writer.h
%{_includedir}/sysprof-6/sysprof-clock.h
%{_includedir}/sysprof-6/sysprof-collector.h
%{_includedir}/sysprof-6/sysprof-macros.h
%{_includedir}/sysprof-6/sysprof-platform.h
%{_includedir}/sysprof-6/sysprof-version.h
%{_includedir}/sysprof-6/sysprof-version-macros.h
%{_libdir}/libsysprof-capture-4.a
%{_libdir}/pkgconfig/sysprof-capture-4.pc
%files devel
%{_includedir}/sysprof-6/
%{_libdir}/libsysprof-6.so
%{_libdir}/pkgconfig/sysprof-6.pc
%{_datadir}/dbus-1/interfaces/org.gnome.Sysprof.Agent.xml
%{_datadir}/dbus-1/interfaces/org.gnome.Sysprof3.Profiler.xml
%{_datadir}/dbus-1/interfaces/org.gnome.Sysprof3.Service.xml
%changelog
%autochangelog