[sysprof/wip/chergert/sysprof-3] libsysprof: use embedded kallsyms when possible



commit 62c8dcf0c788ac60b8af2fe38f9f54e8e6e00da9
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]