[sysprof] libsysprof: use embedded kallsyms when possible
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [sysprof] libsysprof: use embedded kallsyms when possible
- Date: Wed, 29 May 2019 22:48:20 +0000 (UTC)
commit 874fb01c252a736337776ad7b02f5006c983714e
Author: Christian Hergert <chergert redhat com>
Date: Mon May 27 18:05:15 2019 -0700
libsysprof: use embedded kallsyms when possible
This uses the kallysms that has been embedded in the capture file when
that is possible (such as when proc-source appends it).
src/libsysprof/meson.build | 3 +-
src/libsysprof/sysprof-kallsyms.h | 6 +-
src/libsysprof/sysprof-kernel-symbol-resolver.c | 84 +++++++++++++++-
src/libsysprof/sysprof-kernel-symbol.c | 121 +++++++++++++-----------
src/libsysprof/sysprof-kernel-symbol.h | 5 +-
src/libsysprof/sysprof-private.h | 39 ++++++++
src/libsysprof/sysprof.h | 1 -
src/tests/meson.build | 6 --
src/tests/test-kallsyms.c | 2 +
9 files changed, 190 insertions(+), 77 deletions(-)
---
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index 727721a..d225d0c 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -6,7 +6,6 @@ libsysprof_public_sources = [
'sysprof-elf-symbol-resolver.c',
'sysprof-hostinfo-source.c',
'sysprof-jitmap-symbol-resolver.c',
- 'sysprof-kallsyms.c',
'sysprof-kernel-symbol.c',
'sysprof-kernel-symbol-resolver.c',
'sysprof-local-profiler.c',
@@ -29,7 +28,6 @@ libsysprof_public_headers = [
'sysprof-elf-symbol-resolver.h',
'sysprof-hostinfo-source.h',
'sysprof-jitmap-symbol-resolver.h',
- 'sysprof-kallsyms.h',
'sysprof-kernel-symbol.h',
'sysprof-kernel-symbol-resolver.h',
'sysprof-local-profiler.h',
@@ -52,6 +50,7 @@ libsysprof_private_sources = [
'demangle.cpp',
'elfparser.c',
'sysprof-helpers.c',
+ 'sysprof-kallsyms.c',
'sysprof-line-reader.c',
ipc_service_src,
stackstash_sources,
diff --git a/src/libsysprof/sysprof-kallsyms.h b/src/libsysprof/sysprof-kallsyms.h
index 1778f5b..c50303e 100644
--- a/src/libsysprof/sysprof-kallsyms.h
+++ b/src/libsysprof/sysprof-kallsyms.h
@@ -20,22 +20,18 @@
#pragma once
-#include "sysprof-version-macros.h"
+#include <glib.h>
G_BEGIN_DECLS
typedef struct _SysprofKallsyms SysprofKallsyms;
-SYSPROF_AVAILABLE_IN_ALL
SysprofKallsyms *sysprof_kallsyms_new (const gchar *path);
-SYSPROF_AVAILABLE_IN_ALL
SysprofKallsyms *sysprof_kallsyms_new_take (gchar *data);
-SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_kallsyms_next (SysprofKallsyms *self,
const gchar **name,
guint64 *address,
guint8 *type);
-SYSPROF_AVAILABLE_IN_ALL
void sysprof_kallsyms_free (SysprofKallsyms *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofKallsyms, sysprof_kallsyms_free)
diff --git a/src/libsysprof/sysprof-kernel-symbol-resolver.c b/src/libsysprof/sysprof-kernel-symbol-resolver.c
index 4e0f8e2..ee6ec82 100644
--- a/src/libsysprof/sysprof-kernel-symbol-resolver.c
+++ b/src/libsysprof/sysprof-kernel-symbol-resolver.c
@@ -18,14 +18,23 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
+#define G_LOG_DOMAIN "sysprof-kernel-symbol-resolver"
+
#include "config.h"
+#include <unistd.h>
+
+#include "sysprof-kallsyms.h"
#include "sysprof-kernel-symbol.h"
#include "sysprof-kernel-symbol-resolver.h"
+#include "sysprof-private.h"
+
+#include "sysprof-platform.h"
struct _SysprofKernelSymbolResolver
{
- GObject parent_instance;
+ GObject parent_instance;
+ SysprofKernelSymbols *symbols;
};
static GQuark linux_quark;
@@ -38,16 +47,19 @@ sysprof_kernel_symbol_resolver_resolve_with_context (SysprofSymbolResolver *reso
SysprofCaptureAddress address,
GQuark *tag)
{
+ SysprofKernelSymbolResolver *self = (SysprofKernelSymbolResolver *)resolver;
const SysprofKernelSymbol *sym;
- g_assert (SYSPROF_IS_SYMBOL_RESOLVER (resolver));
+ g_assert (SYSPROF_IS_SYMBOL_RESOLVER (self));
+ g_assert (tag != NULL);
if (context != SYSPROF_ADDRESS_CONTEXT_KERNEL)
return NULL;
- sym = sysprof_kernel_symbol_from_address (address);
+ if (self->symbols == NULL)
+ return NULL;
- if (sym != NULL)
+ if ((sym = _sysprof_kernel_symbols_lookup (self->symbols, address)))
{
*tag = linux_quark;
return g_strdup (sym->name);
@@ -56,9 +68,59 @@ sysprof_kernel_symbol_resolver_resolve_with_context (SysprofSymbolResolver *reso
return NULL;
}
+static void
+sysprof_kernel_symbol_resolver_load (SysprofSymbolResolver *resolver,
+ SysprofCaptureReader *reader)
+{
+ static const guint8 zero[] = {0};
+ SysprofKernelSymbolResolver *self = (SysprofKernelSymbolResolver *)resolver;
+ g_autoptr(GByteArray) bytes = NULL;
+ g_autoptr(SysprofKallsyms) kallsyms = NULL;
+ guint8 buf[4096];
+ gint data_fd;
+
+ g_assert (SYSPROF_IS_KERNEL_SYMBOL_RESOLVER (self));
+ g_assert (reader != NULL);
+
+ if (-1 == (data_fd = sysprof_memfd_create ("[sysprof-kallsyms]")) ||
+ !sysprof_capture_reader_read_file_fd (reader, "/proc/kallsyms", data_fd))
+ {
+ if (data_fd != -1)
+ close (data_fd);
+ self->symbols = _sysprof_kernel_symbols_ref_shared ();
+ return;
+ }
+
+ bytes = g_byte_array_new ();
+ lseek (data_fd, 0, SEEK_SET);
+
+ for (;;)
+ {
+ gssize len = read (data_fd, buf, sizeof buf);
+
+ if (len <= 0)
+ break;
+
+ g_byte_array_append (bytes, buf, len);
+ }
+
+ g_byte_array_append (bytes, zero, 1);
+
+ if (bytes->len > 1)
+ {
+ kallsyms = sysprof_kallsyms_new_take ((gchar *)g_byte_array_free (g_steal_pointer (&bytes), FALSE));
+ self->symbols = _sysprof_kernel_symbols_new_from_kallsyms (kallsyms);
+ }
+ else
+ {
+ self->symbols = _sysprof_kernel_symbols_ref_shared ();
+ }
+}
+
static void
symbol_resolver_iface_init (SysprofSymbolResolverInterface *iface)
{
+ iface->load = sysprof_kernel_symbol_resolver_load;
iface->resolve_with_context = sysprof_kernel_symbol_resolver_resolve_with_context;
}
@@ -68,9 +130,23 @@ G_DEFINE_TYPE_WITH_CODE (SysprofKernelSymbolResolver,
G_IMPLEMENT_INTERFACE (SYSPROF_TYPE_SYMBOL_RESOLVER,
symbol_resolver_iface_init))
+static void
+sysprof_kernel_symbol_resolver_finalize (GObject *object)
+{
+ SysprofKernelSymbolResolver *self = (SysprofKernelSymbolResolver *)object;
+
+ g_clear_pointer (&self->symbols, g_array_unref);
+
+ G_OBJECT_CLASS (sysprof_kernel_symbol_resolver_parent_class)->finalize (object);
+}
+
static void
sysprof_kernel_symbol_resolver_class_init (SysprofKernelSymbolResolverClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = sysprof_kernel_symbol_resolver_finalize;
+
linux_quark = g_quark_from_static_string ("Kernel");
}
diff --git a/src/libsysprof/sysprof-kernel-symbol.c b/src/libsysprof/sysprof-kernel-symbol.c
index 7c75d5d..3213c8b 100644
--- a/src/libsysprof/sysprof-kernel-symbol.c
+++ b/src/libsysprof/sysprof-kernel-symbol.c
@@ -28,11 +28,12 @@
#include "sysprof-helpers.h"
#include "sysprof-kallsyms.h"
#include "sysprof-kernel-symbol.h"
+#include "sysprof-private.h"
-static GArray *kernel_symbols;
+static G_LOCK_DEFINE (kernel_lock);
static GStringChunk *kernel_symbol_strs;
-static GHashTable *kernel_symbols_skip_hash;
-static const gchar *kernel_symbols_skip[] = {
+static GHashTable *kernel_symbols_skip_hash;
+static const gchar *kernel_symbols_skip[] = {
/* IRQ stack */
"common_interrupt",
"apic_timer_interrupt",
@@ -65,6 +66,13 @@ static const gchar *kernel_symbols_skip[] = {
"perf_callchain",
};
+static inline gboolean
+type_is_ignored (guint8 type)
+{
+ /* Only allow symbols in the text (code) section */
+ return (type != 't' && type != 'T');
+}
+
static gint
sysprof_kernel_symbol_compare (gconstpointer a,
gconstpointer b)
@@ -80,37 +88,41 @@ sysprof_kernel_symbol_compare (gconstpointer a,
return -1;
}
-static inline gboolean
-type_is_ignored (guint8 type)
+static void
+do_shared_init (void)
{
- /* Only allow symbols in the text (code) section */
- return (type != 't' && type != 'T');
+ static gsize once;
+
+ if (g_once_init_enter (&once))
+ {
+ g_autoptr(GHashTable) skip = NULL;
+
+ kernel_symbol_strs = g_string_chunk_new (4096 * 4);
+
+ skip = g_hash_table_new (g_str_hash, g_str_equal);
+ for (guint i = 0; i < G_N_ELEMENTS (kernel_symbols_skip); i++)
+ g_hash_table_insert (skip, (gchar *)kernel_symbols_skip[i], NULL);
+ kernel_symbols_skip_hash = g_steal_pointer (&skip);
+
+ g_once_init_leave (&once, TRUE);
+ }
}
-static gboolean
-sysprof_kernel_symbol_load (void)
+SysprofKernelSymbols *
+_sysprof_kernel_symbols_new_from_kallsyms (SysprofKallsyms *kallsyms)
{
- SysprofHelpers *helpers = sysprof_helpers_get_default ();
- g_autoptr(SysprofKallsyms) kallsyms = NULL;
- g_autoptr(GHashTable) skip = NULL;
- g_autoptr(GArray) ar = NULL;
- g_autofree gchar *contents = NULL;
+ SysprofKernelSymbols *self;
const gchar *name;
guint64 addr;
guint8 type;
- skip = g_hash_table_new (g_str_hash, g_str_equal);
- for (guint i = 0; i < G_N_ELEMENTS (kernel_symbols_skip); i++)
- g_hash_table_insert (skip, (gchar *)kernel_symbols_skip[i], NULL);
- kernel_symbols_skip_hash = g_steal_pointer (&skip);
+ do_shared_init ();
- if (!sysprof_helpers_get_proc_file (helpers, "/proc/kallsyms", NULL, &contents, NULL))
- return FALSE;
+ g_return_val_if_fail (kallsyms != NULL, NULL);
- kernel_symbol_strs = g_string_chunk_new (4096 * 4);
- kallsyms = sysprof_kallsyms_new_take (g_steal_pointer (&contents));
- ar = g_array_new (FALSE, FALSE, sizeof (SysprofKernelSymbol));
+ self = g_array_new (FALSE, FALSE, sizeof (SysprofKernelSymbol));
+ G_LOCK (kernel_lock);
while (sysprof_kallsyms_next (kallsyms, &name, &addr, &type))
{
if (!type_is_ignored (type))
@@ -120,25 +132,34 @@ sysprof_kernel_symbol_load (void)
sym.address = addr;
sym.name = g_string_chunk_insert_const (kernel_symbol_strs, name);
- g_array_append_val (ar, sym);
+ g_array_append_val (self, sym);
}
}
+ G_UNLOCK (kernel_lock);
+
+ g_array_sort (self, sysprof_kernel_symbol_compare);
- g_array_sort (ar, sysprof_kernel_symbol_compare);
+ return g_steal_pointer (&self);
+}
-#if 0
- g_print ("First: 0x%lx Last: 0x%lx\n",
- g_array_index (ar, SysprofKernelSymbol, 0).address,
- g_array_index (ar, SysprofKernelSymbol, ar->len - 1).address);
-#endif
+SysprofKernelSymbols *
+_sysprof_kernel_symbols_ref_shared (void)
+{
+ static SysprofKernelSymbols *shared;
- if (ar->len > 0)
+ if (shared == NULL)
{
- kernel_symbols = g_steal_pointer (&ar);
- return TRUE;
+ SysprofHelpers *helpers = sysprof_helpers_get_default ();
+ g_autofree gchar *contents = NULL;
+
+ if (sysprof_helpers_get_proc_file (helpers, "/proc/kallsyms", NULL, &contents, NULL))
+ {
+ g_autoptr(SysprofKallsyms) kallsyms = sysprof_kallsyms_new_take (g_steal_pointer (&contents));
+ shared = _sysprof_kernel_symbols_new_from_kallsyms (kallsyms);
+ }
}
- return FALSE;
+ return g_array_ref (shared);
}
static const SysprofKernelSymbol *
@@ -174,8 +195,9 @@ sysprof_kernel_symbol_lookup (SysprofKernelSymbol *symbols,
}
}
-/**
- * sysprof_kernel_symbol_from_address:
+/*
+ * sysprof_kernel_symbols_lookup:
+ * @self: the symbol data to lookup
* @address: the address of the instruction pointer
*
* Locates the kernel symbol that contains @address.
@@ -183,37 +205,26 @@ sysprof_kernel_symbol_lookup (SysprofKernelSymbol *symbols,
* Returns: (transfer none): An #SysprofKernelSymbol or %NULL.
*/
const SysprofKernelSymbol *
-sysprof_kernel_symbol_from_address (SysprofCaptureAddress address)
+_sysprof_kernel_symbols_lookup (const SysprofKernelSymbols *self,
+ SysprofCaptureAddress address)
{
const SysprofKernelSymbol *first;
const SysprofKernelSymbol *ret;
- if G_UNLIKELY (kernel_symbols == NULL)
- {
- static gboolean failed;
-
- if (failed)
- return NULL;
+ g_assert (self != NULL);
- if (!sysprof_kernel_symbol_load ())
- {
- failed = TRUE;
- return NULL;
- }
- }
-
- g_assert (kernel_symbols != NULL);
- g_assert (kernel_symbols->len > 0);
+ if (self->len == 0)
+ return NULL;
/* Short circuit if this is out of range */
- first = &g_array_index (kernel_symbols, SysprofKernelSymbol, 0);
+ first = &g_array_index (self, SysprofKernelSymbol, 0);
if (address < first->address)
return NULL;
- ret = sysprof_kernel_symbol_lookup ((SysprofKernelSymbol *)(gpointer)kernel_symbols->data,
+ ret = sysprof_kernel_symbol_lookup ((SysprofKernelSymbol *)(gpointer)self->data,
address,
0,
- kernel_symbols->len - 1);
+ self->len - 1);
/* We resolve all symbols, including ignored symbols so that we
* don't give back the wrong function juxtapose an ignored func.
diff --git a/src/libsysprof/sysprof-kernel-symbol.h b/src/libsysprof/sysprof-kernel-symbol.h
index af9e7ca..7ef72f0 100644
--- a/src/libsysprof/sysprof-kernel-symbol.h
+++ b/src/libsysprof/sysprof-kernel-symbol.h
@@ -31,10 +31,7 @@ G_BEGIN_DECLS
typedef struct
{
SysprofCaptureAddress address;
- const gchar *name;
+ const gchar *name;
} SysprofKernelSymbol;
-SYSPROF_AVAILABLE_IN_ALL
-const SysprofKernelSymbol *sysprof_kernel_symbol_from_address (SysprofCaptureAddress address);
-
G_END_DECLS
diff --git a/src/libsysprof/sysprof-private.h b/src/libsysprof/sysprof-private.h
new file mode 100644
index 0000000..83eabe4
--- /dev/null
+++ b/src/libsysprof/sysprof-private.h
@@ -0,0 +1,39 @@
+/* sysprof-private.h
+ *
+ * Copyright 2019 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-capture.h>
+
+#include "sysprof.h"
+#include "sysprof-kallsyms.h"
+
+G_BEGIN_DECLS
+
+typedef GArray SysprofKernelSymbols;
+
+SysprofKernelSymbols *_sysprof_kernel_symbols_ref_shared (void);
+SysprofKernelSymbols *_sysprof_kernel_symbols_new_from_kallsyms (SysprofKallsyms *kallsyms);
+const SysprofKernelSymbol *_sysprof_kernel_symbols_lookup (const SysprofKernelSymbols *self,
+ SysprofCaptureAddress address);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofKernelSymbols, g_array_unref)
+
+G_END_DECLS
diff --git a/src/libsysprof/sysprof.h b/src/libsysprof/sysprof.h
index a88f47a..2a73501 100644
--- a/src/libsysprof/sysprof.h
+++ b/src/libsysprof/sysprof.h
@@ -27,7 +27,6 @@ G_BEGIN_DECLS
# include "sysprof-callgraph-profile.h"
# include "sysprof-capture-gobject.h"
# include "sysprof-local-profiler.h"
-# include "sysprof-kallsyms.h"
# include "sysprof-profile.h"
# include "sysprof-profiler.h"
# include "sysprof-map-lookaside.h"
diff --git a/src/tests/meson.build b/src/tests/meson.build
index a519283..6d3cf64 100644
--- a/src/tests/meson.build
+++ b/src/tests/meson.build
@@ -27,12 +27,6 @@ test_capture_cursor = executable('test-capture-cursor', 'test-capture-cursor.c',
test('test-capture', test_capture, env: test_env)
test('test-capture-cursor', test_capture_cursor, env: test_env)
-# Use ./tests/test-kallsyms /proc/kallsyms to test (as user or root)
-test_kallsyms = executable('test-kallsyms', 'test-kallsyms.c',
- c_args: test_cflags,
- dependencies: test_deps,
-)
-
if get_option('enable_gtk')
test_ui_deps = [
diff --git a/src/tests/test-kallsyms.c b/src/tests/test-kallsyms.c
index c7ef0bc..4b8dff5 100644
--- a/src/tests/test-kallsyms.c
+++ b/src/tests/test-kallsyms.c
@@ -2,6 +2,8 @@
#include <stdlib.h>
#include <sysprof.h>
+#include "sysprof-kallsyms.h"
+
int
main (gint argc,
gchar *argv[])
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]