From 5c825c1fb5709e237688a0825ce31e544e658404 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 30 May 2023 17:06:28 -0700 Subject: [PATCH] libsysprof-profile: add some basic process information This needs to get into the capture, and we still need to respond to the discovery of new processes as well (which we lack API for). --- .../sysprof-linux-instrument.c | 112 +++++++++++++++++- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/src/libsysprof-profile/sysprof-linux-instrument.c b/src/libsysprof-profile/sysprof-linux-instrument.c index 44eaf9d2..b0300648 100644 --- a/src/libsysprof-profile/sysprof-linux-instrument.c +++ b/src/libsysprof-profile/sysprof-linux-instrument.c @@ -43,17 +43,121 @@ sysprof_linux_instrument_list_required_policy (SysprofInstrument *instrument) return g_strdupv ((char **)policy); } +static void +add_process_info (SysprofRecording *recording, + GVariant *process_info_reply) +{ + g_autoptr(GPtrArray) futures = NULL; + g_autoptr(GVariant) process_info = NULL; + SysprofCaptureWriter *writer; + GVariantIter iter; + GVariant *pidinfo; + + g_assert (process_info_reply != NULL); + g_assert (g_variant_is_of_type (process_info_reply, G_VARIANT_TYPE ("(aa{sv})"))); + + writer = _sysprof_recording_writer (recording); + + /* Loop through all the PIDs the server notified us about */ + process_info = g_variant_get_child_value (process_info_reply, 0); + g_variant_iter_init (&iter, process_info); + while (g_variant_iter_loop (&iter, "@a{sv}", &pidinfo)) + { + g_autofree char *mount_path = NULL; + GVariantDict dict; + const char *cmdline; + const char *comm; + const char *mountinfo; + const char *maps; + const char *cgroup; + gint32 pid; + + g_variant_dict_init (&dict, pidinfo); + + if (!g_variant_dict_lookup (&dict, "pid", "i", &pid)) + goto skip; + + if (!g_variant_dict_lookup (&dict, "cmdline", "&s", &cmdline)) + cmdline = ""; + + if (!g_variant_dict_lookup (&dict, "comm", "&s", &comm)) + comm = ""; + + if (!g_variant_dict_lookup (&dict, "mountinfo", "&s", &mountinfo)) + mountinfo = ""; + + if (!g_variant_dict_lookup (&dict, "maps", "&s", &maps)) + maps = ""; + + if (!g_variant_dict_lookup (&dict, "cgroup", "&s", &cgroup)) + cgroup = ""; + + /* Notify the capture that a process was spawned */ + sysprof_capture_writer_add_process (writer, + SYSPROF_CAPTURE_CURRENT_TIME, + -1, + pid, + *cmdline ? cmdline : comm); + + /* Give the capture access to the mountinfo of that process to aid + * in resolving symbols later on. + */ + mount_path = g_strdup_printf ("/proc/%u/mountinfo", pid); + _sysprof_recording_add_file_data (recording, mount_path, mountinfo, -1); + + // TODO + //sysprof_proc_source_populate_maps (self, pid, maps, ignore_inode); + //sysprof_proc_source_populate_overlays (self, pid, cgroup); + + skip: + g_variant_dict_clear (&dict); + } +} + static DexFuture * sysprof_linux_instrument_prepare_fiber (gpointer user_data) { SysprofRecording *recording = user_data; + g_autoptr(GDBusConnection) bus = NULL; + g_autoptr(GVariant) process_info_reply = NULL; + g_autoptr(GVariant) process_info = NULL; + g_autoptr(GError) error = NULL; g_assert (SYSPROF_IS_RECORDING (recording)); - return dex_future_all (_sysprof_recording_add_file (recording, "/proc/kallsyms", TRUE), - _sysprof_recording_add_file (recording, "/proc/cpuinfo", TRUE), - _sysprof_recording_add_file (recording, "/proc/mounts", TRUE), - NULL); + /* First get some basic information about the system into the capture. We can + * get the contents for all of these concurrently. + */ + if (!dex_await (dex_future_all (_sysprof_recording_add_file (recording, "/proc/kallsyms", TRUE), + _sysprof_recording_add_file (recording, "/proc/cpuinfo", TRUE), + _sysprof_recording_add_file (recording, "/proc/mounts", TRUE), + NULL), + &error)) + return dex_future_new_for_error (g_steal_pointer (&error)); + + /* We need access to the bus to call various sysprofd API directly */ + if (!(bus = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error))) + return dex_future_new_for_error (g_steal_pointer (&error)); + + /* We also want to get a bunch of info on user processes so that we can add + * records about them to the recording. + */ + if (!(process_info_reply = dex_await_variant (dex_dbus_connection_call (bus, + "org.gnome.Sysprof3", + "/org/gnome/Sysprof3", + "org.gnome.Sysprof3.Service", + "GetProcessInfo", + g_variant_new ("(s)", "pid,maps,mountinfo,cmdline,comm,cgroup"), + G_VARIANT_TYPE ("(aa{sv})"), + G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION, + G_MAXINT), + &error))) + return dex_future_new_for_error (g_steal_pointer (&error)); + + /* Add process records for each of the processes discovered */ + add_process_info (recording, process_info_reply); + + return dex_future_new_for_boolean (TRUE); } static DexFuture *