libsysprof-analyze: parse core mount namespace devices

We want to track the core mount namespace, for which the namespace we
use for processes will derive (to be done).
This commit is contained in:
Christian Hergert
2023-05-09 17:20:00 -07:00
parent f01346da90
commit 6290a1736d

View File

@ -32,8 +32,12 @@
#include "sysprof-document-frame-private.h"
#include "sysprof-document-mmap.h"
#include "sysprof-document-symbols-private.h"
#include "sysprof-mount-device-private.h"
#include "sysprof-mount-namespace-private.h"
#include "sysprof-symbolizer-private.h"
#include "line-reader-private.h"
struct _SysprofDocument
{
GObject parent_instance;
@ -50,6 +54,8 @@ struct _SysprofDocument
GHashTable *files_first_position;
GHashTable *pid_to_mmaps;
SysprofMountNamespace *mount_namespace;
GMutex strings_mutex;
GHashTable *strings;
@ -112,6 +118,18 @@ _sysprof_document_traceables (SysprofDocument *self)
return self->traceables;
}
static void
decode_space (gchar **str)
{
/* Replace encoded space "\040" with ' ' */
if (strstr (*str, "\\040"))
{
g_auto(GStrv) parts = g_strsplit (*str, "\\040", 0);
g_free (*str);
*str = g_strjoinv (" ", parts);
}
}
static inline gboolean
has_null_byte (const char *str,
const char *endptr)
@ -140,6 +158,8 @@ sysprof_document_finalize (GObject *object)
g_clear_pointer (&self->mmaps, gtk_bitset_unref);
g_clear_pointer (&self->file_chunks, gtk_bitset_unref);
g_clear_object (&self->mount_namespace);
g_clear_pointer (&self->files_first_position, g_hash_table_unref);
g_mutex_clear (&self->strings_mutex);
@ -170,6 +190,8 @@ sysprof_document_init (SysprofDocument *self)
self->files_first_position = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
self->pid_to_mmaps = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_ptr_array_unref);
self->mount_namespace = sysprof_mount_namespace_new ();
}
static int
@ -226,6 +248,82 @@ sysprof_document_load_memory_maps (SysprofDocument *self)
}
}
static void
sysprof_document_load_mounts (SysprofDocument *self)
{
g_autoptr(SysprofDocumentFile) file = NULL;
g_autoptr(GBytes) bytes = NULL;
LineReader reader;
const char *contents;
gsize contents_len;
gsize line_len;
char *line;
g_assert (SYSPROF_IS_DOCUMENT (self));
if (!(file = sysprof_document_lookup_file (self, "/proc/mounts")) ||
!(bytes = sysprof_document_file_dup_bytes (file)))
return;
contents = g_bytes_get_data (bytes, &contents_len);
g_assert (contents != NULL);
g_assert (contents[contents_len] == 0);
line_reader_init (&reader, (char *)contents, contents_len);
while ((line = line_reader_next (&reader, &line_len)))
{
g_autoptr(SysprofMountDevice) mount_device = NULL;
g_auto(GStrv) parts = NULL;
g_autofree char *subvol = NULL;
const char *filesystem;
const char *mountpoint;
const char *device;
const char *options;
line[line_len] = 0;
parts = g_strsplit (line, " ", 5);
/* Field 0: device
* Field 1: mountpoint
* Field 2: filesystem
* Field 3: Options
* .. Ignored ..
*/
if (g_strv_length (parts) != 5)
continue;
for (guint j = 0; parts[j]; j++)
decode_space (&parts[j]);
device = parts[0];
mountpoint = parts[1];
filesystem = parts[2];
options = parts[3];
if (g_strcmp0 (filesystem, "btrfs") == 0)
{
g_auto(GStrv) opts = g_strsplit (options, ",", 0);
for (guint k = 0; opts[k]; k++)
{
if (g_str_has_prefix (opts[k], "subvol="))
{
subvol = g_strdup (opts[k] + strlen ("subvol="));
break;
}
}
}
mount_device = sysprof_mount_device_new ();
sysprof_mount_device_set_id (mount_device, device);
sysprof_mount_device_set_mount_path (mount_device, mountpoint);
sysprof_mount_device_set_subvolume (mount_device, subvol);
sysprof_mount_namespace_add_device (self->mount_namespace, g_steal_pointer (&mount_device));
}
}
static gboolean
sysprof_document_load (SysprofDocument *self,
int capture_fd,
@ -306,6 +404,7 @@ sysprof_document_load (SysprofDocument *self,
g_array_append_val (self->frames, ptr);
}
sysprof_document_load_mounts (self);
sysprof_document_load_memory_maps (self);
return TRUE;