diff --git a/src/libsysprof-analyze/sysprof-elf-loader-private.h b/src/libsysprof-analyze/sysprof-elf-loader-private.h index bfc0d74b..363ca751 100644 --- a/src/libsysprof-analyze/sysprof-elf-loader-private.h +++ b/src/libsysprof-analyze/sysprof-elf-loader-private.h @@ -43,6 +43,7 @@ SysprofElf *sysprof_elf_loader_load (SysprofElfLoader SysprofMountNamespace *mount_namespace, const char *file, const char *build_id, + guint64 file_inode, GError **error); diff --git a/src/libsysprof-analyze/sysprof-elf-loader.c b/src/libsysprof-analyze/sysprof-elf-loader.c index 6c40fb34..c0e0396a 100644 --- a/src/libsysprof-analyze/sysprof-elf-loader.c +++ b/src/libsysprof-analyze/sysprof-elf-loader.c @@ -270,6 +270,7 @@ sysprof_elf_loader_annotate (SysprofElfLoader *self, g_autofree char *directory_name = NULL; g_autofree char *debug_path = NULL; g_autofree char *container_path = NULL; + const char *build_id; g_assert (SYSPROF_IS_ELF_LOADER (self)); g_assert (SYSPROF_IS_MOUNT_NAMESPACE (mount_namespace)); @@ -278,8 +279,9 @@ sysprof_elf_loader_annotate (SysprofElfLoader *self, directory_name = g_path_get_dirname (orig_file); debug_path = g_build_filename ("/usr/lib/debug", directory_name, debug_link, NULL); + build_id = sysprof_elf_get_build_id (elf); - if ((debug_link_elf = sysprof_elf_loader_load (self, mount_namespace, debug_path, NULL, NULL))) + if ((debug_link_elf = sysprof_elf_loader_load (self, mount_namespace, debug_path, build_id, 0, NULL))) sysprof_elf_set_debug_link_elf (elf, get_deepest_debuglink (debug_link_elf)); } @@ -290,6 +292,8 @@ sysprof_elf_loader_annotate (SysprofElfLoader *self, * @file: the path of the file to load within the mount namespace * @build_id: (nullable): an optional build-id that can be used to resolve * the file alternatively to the file path + * @file_inode: expected inode for @file + * @error: a location for a #GError, or %NULL * * Attempts to load a #SysprofElf for @file (or optionally by @build_id). * @@ -305,6 +309,7 @@ sysprof_elf_loader_load (SysprofElfLoader *self, SysprofMountNamespace *mount_namespace, const char *file, const char *build_id, + guint64 file_inode, GError **error) { g_auto(GStrv) paths = NULL; @@ -355,8 +360,20 @@ sysprof_elf_loader_load (SysprofElfLoader *self, g_strdup (path), elf ? g_object_ref (elf) : NULL); - if (elf && (debug_link = sysprof_elf_get_debug_link (elf))) - sysprof_elf_loader_annotate (self, mount_namespace, file, elf, debug_link); + if (elf != NULL) + { + if ((debug_link = sysprof_elf_get_debug_link (elf))) + sysprof_elf_loader_annotate (self, mount_namespace, file, elf, debug_link); + + /* If we loaded the ELF, but it doesn't match what this request is looking + * for in terms of inode/build-id, then we need to bail and not return it. + * We can, however, leave it in the cache incase another process/sample + * will need the ELF. + */ + if (!sysprof_elf_matches (elf, file_inode, build_id)) + g_clear_object (&elf); + } + return g_steal_pointer (&elf); } diff --git a/src/libsysprof-analyze/sysprof-elf-private.h b/src/libsysprof-analyze/sysprof-elf-private.h index 12775271..7dda3a36 100644 --- a/src/libsysprof-analyze/sysprof-elf-private.h +++ b/src/libsysprof-analyze/sysprof-elf-private.h @@ -31,6 +31,9 @@ G_DECLARE_FINAL_TYPE (SysprofElf, sysprof_elf, SYSPROF, ELF, GObject) SysprofElf *sysprof_elf_new (const char *filename, GMappedFile *mapped_file, GError **error); +gboolean sysprof_elf_matches (SysprofElf *self, + guint64 file_inode, + const char *build_id); const char *sysprof_elf_get_file (SysprofElf *self); const char *sysprof_elf_get_build_id (SysprofElf *self); const char *sysprof_elf_get_debug_link (SysprofElf *self); diff --git a/src/libsysprof-analyze/sysprof-elf.c b/src/libsysprof-analyze/sysprof-elf.c index 9a241e8c..c19cb080 100644 --- a/src/libsysprof-analyze/sysprof-elf.c +++ b/src/libsysprof-analyze/sysprof-elf.c @@ -31,6 +31,7 @@ struct _SysprofElf char *file; SysprofElf *debug_link_elf; ElfParser *parser; + guint64 file_inode; }; enum { @@ -259,3 +260,25 @@ sysprof_elf_set_debug_link_elf (SysprofElf *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]); } + +gboolean +sysprof_elf_matches (SysprofElf *self, + guint64 file_inode, + const char *build_id) +{ + g_return_val_if_fail (SYSPROF_IS_ELF (self), FALSE); + + if (build_id != NULL) + { + const char *elf_build_id = elf_parser_get_build_id (self->parser); + + /* Not matching build-id, you definitely don't want this ELF */ + if (elf_build_id != NULL && !g_str_equal (build_id, elf_build_id)) + return FALSE; + } + + if (file_inode && self->file_inode && file_inode != self->file_inode) + return FALSE; + + return TRUE; +} diff --git a/src/libsysprof-analyze/tests/test-elf-loader.c b/src/libsysprof-analyze/tests/test-elf-loader.c index 73616e0b..e1c0c67d 100644 --- a/src/libsysprof-analyze/tests/test-elf-loader.c +++ b/src/libsysprof-analyze/tests/test-elf-loader.c @@ -69,7 +69,8 @@ main (int argc, g_autoptr(SysprofDocumentMmap) memory_map = g_list_model_get_item (memory_maps, j); const char *file = sysprof_document_mmap_get_file (memory_map); const char *build_id = sysprof_document_mmap_get_build_id (memory_map); - g_autoptr(SysprofElf) elf = sysprof_elf_loader_load (elf_loader, info->mount_namespace, file, build_id, &error); + guint64 file_inode = sysprof_document_mmap_get_file_inode (memory_map); + g_autoptr(SysprofElf) elf = sysprof_elf_loader_load (elf_loader, info->mount_namespace, file, build_id, file_inode, &error); if (elf == NULL) g_print ("%u: %s [unresolved]\n", info->pid, file);