diff --git a/lib/Makefile.am b/lib/Makefile.am index 133bf23f..a0b6d137 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -68,6 +68,7 @@ headers_DATA = \ sp-profiler.h \ sp-selection.h \ sp-source.h \ + sp-symbol-dirs.h \ sp-symbol-resolver.h \ $(NULL) @@ -102,6 +103,7 @@ libsysprof_@API_VERSION@_la_SOURCES = \ sp-profiler.c \ sp-selection.c \ sp-source.c \ + sp-symbol-dirs.c \ sp-symbol-resolver.c \ $(NULL) diff --git a/lib/sp-elf-symbol-resolver.c b/lib/sp-elf-symbol-resolver.c index 8d78d86d..9002606e 100644 --- a/lib/sp-elf-symbol-resolver.c +++ b/lib/sp-elf-symbol-resolver.c @@ -135,7 +135,16 @@ sp_elf_symbol_resolver_get_bin_file (SpElfSymbolResolver *self, if (bin_file == NULL) { - bin_file = bin_file_new (filename); + const gchar *alternate = filename; + + /* + * If we are in a new mount namespace, then rely on the sp_symbol_dirs + * to find us a locate to resolve the file where the CRC will match. + */ + if (g_str_has_prefix (filename, "/newroot/")) + alternate += strlen ("/newroot"); + + bin_file = bin_file_new (alternate); g_hash_table_insert (self->bin_files, g_strdup (filename), bin_file); } @@ -268,8 +277,15 @@ sp_elf_symbol_resolver_resolve (SpSymbolResolver *resolver, g_assert (bin_file != NULL); - if (map->inode && !bin_file_check_inode (bin_file, map->inode)) - return g_strdup_printf ("%s: inode mismatch", map->filename); + /* + * Ensure we have a valid inode mapping, unless it was in a /newroot/, for + * which those won't be reliable. + */ + if (!g_str_has_prefix (map->filename, "/newroot/")) + { + if (map->inode && !bin_file_check_inode (bin_file, map->inode)) + return g_strdup_printf ("%s: inode mismatch", map->filename); + } bin_sym = bin_file_lookup_symbol (bin_file, address); bin_sym_name = bin_symbol_get_name (bin_file, bin_sym); diff --git a/lib/sp-symbol-dirs.c b/lib/sp-symbol-dirs.c new file mode 100644 index 00000000..51190dba --- /dev/null +++ b/lib/sp-symbol-dirs.c @@ -0,0 +1,124 @@ +/* sp-symbol-dirs.c + * + * Copyright (C) 2017 Christian Hergert + * + * 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 . + */ + +#include "config.h" + +#include "sp-symbol-dirs.h" + +static GPtrArray *sp_symbol_dirs; + +G_LOCK_DEFINE (sp_symbol_dirs); + +static GPtrArray * +sp_get_symbol_dirs_locked (void) +{ + if (sp_symbol_dirs == NULL) + { + sp_symbol_dirs = g_ptr_array_new (); + g_ptr_array_add (sp_symbol_dirs, g_strdup ("/usr/lib/debug")); + } + + return sp_symbol_dirs; +} + +void +sp_symbol_dirs_add (const gchar *path) +{ + GPtrArray *ar; + + G_LOCK (sp_symbol_dirs); + + ar = sp_get_symbol_dirs_locked (); + + for (guint i = 0; i < ar->len; i++) + { + const gchar *ele = g_ptr_array_index (ar, i); + + if (g_strcmp0 (path, ele) == 0) + goto skip; + } + + g_ptr_array_add (ar, g_strdup (path)); + +skip: + G_UNLOCK (sp_symbol_dirs); +} + +void +sp_symbol_dirs_remove (const gchar *path) +{ + GPtrArray *ar; + + G_LOCK (sp_symbol_dirs); + + ar = sp_get_symbol_dirs_locked (); + + for (guint i = 0; i < ar->len; i++) + { + const gchar *ele = g_ptr_array_index (ar, i); + + if (g_strcmp0 (path, ele) == 0) + { + g_ptr_array_remove_index (ar, i); + break; + } + } + + G_UNLOCK (sp_symbol_dirs); +} + +/** + * sp_symbol_dirs_get_paths: + * @dir: the directory containing the library + * @name: the name of the file in @dir + * + * This function will build an array of files to look at to resolve the + * debug symbols for the file at path "dir/name". + * + * Returns: (transfer full): A #GStrv of possible paths. + */ +gchar ** +sp_symbol_dirs_get_paths (const gchar *dir, + const gchar *name) +{ + GPtrArray *ret = g_ptr_array_new (); + GPtrArray *ar; + + g_ptr_array_add (ret, g_build_filename (dir, name, NULL)); + + G_LOCK (sp_symbol_dirs); + + ar = sp_get_symbol_dirs_locked (); + + for (guint i = 0; i < ar->len; i++) + { + const gchar *ele = g_ptr_array_index (ar, i); + + g_ptr_array_add (ret, g_build_filename (ele, name, NULL)); + g_ptr_array_add (ret, g_build_filename (ele, dir, name, NULL)); + } + + g_ptr_array_add (ret, g_build_filename (dir, ".debug", name, NULL)); + g_ptr_array_add (ret, g_build_filename (DEBUGDIR, dir, name, NULL)); + + G_UNLOCK (sp_symbol_dirs); + + g_ptr_array_add (ret, NULL); + + return (gchar **)g_ptr_array_free (ret, FALSE); +} diff --git a/lib/sp-symbol-dirs.h b/lib/sp-symbol-dirs.h new file mode 100644 index 00000000..8149ad7d --- /dev/null +++ b/lib/sp-symbol-dirs.h @@ -0,0 +1,33 @@ +/* sp-symbol-dirs.h + * + * Copyright (C) 2017 Christian Hergert + * + * 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 . + */ + +#ifndef SP_SYMBOL_DIRS_H +#define SP_SYMBOL_DIRS_H + +#include + +G_BEGIN_DECLS + +void sp_symbol_dirs_add (const gchar *dir); +void sp_symbol_dirs_remove (const gchar *dir); +gchar **sp_symbol_dirs_get_paths (const gchar *dir, + const gchar *name); + +G_END_DECLS + +#endif /* SP_SYMBOL_DIRS_H */ diff --git a/lib/sysprof.h b/lib/sysprof.h index 22aed205..4dc1c1ab 100644 --- a/lib/sysprof.h +++ b/lib/sysprof.h @@ -46,6 +46,7 @@ G_BEGIN_DECLS # include "sp-profiler.h" # include "sp-selection.h" # include "sp-source.h" +# include "sp-symbol-dirs.h" # include "sp-symbol-resolver.h" # include "sysprof-version.h" #undef SYSPROF_INSIDE diff --git a/lib/util/binfile.c b/lib/util/binfile.c index a30c088f..1b02978e 100644 --- a/lib/util/binfile.c +++ b/lib/util/binfile.c @@ -38,6 +38,8 @@ #include "binfile.h" #include "elfparser.h" +#include "../sp-symbol-dirs.h" + struct bin_file_t { int ref_count; @@ -88,8 +90,6 @@ already_warned (const char *name) return FALSE; } -static const char *const debug_file_directory = DEBUGDIR; - static ElfParser * get_build_id_file (ElfParser *elf) { @@ -114,8 +114,7 @@ get_build_id_file (ElfParser *elf) "/usr", "lib", "debug", ".build-id", init, rest, NULL); tries = g_list_append (tries, tmp); - tmp = g_build_filename ( - debug_file_directory, ".build-id", init, rest, NULL); + tmp = g_build_filename (DEBUGDIR, ".build-id", init, rest, NULL); tries = g_list_append (tries, tmp); for (list = tries; list != NULL; list = list->next) @@ -151,13 +150,13 @@ get_debuglink_file (ElfParser *elf, const char *filename, char **new_name) { -#define N_TRIES 4 const char *basename; char *dir; guint32 crc32; - GList *tries = NULL, *list; + gchar **tries; ElfParser *result = NULL; const char *build_id; + guint i; if (!elf) return NULL; @@ -175,14 +174,11 @@ get_debuglink_file (ElfParser *elf, dir = g_path_get_dirname (filename); - tries = g_list_append (tries, g_build_filename (dir, basename, NULL)); - tries = g_list_append (tries, g_build_filename (dir, ".debug", basename, NULL)); - tries = g_list_append (tries, g_build_filename ("/usr", "lib", "debug", dir, basename, NULL)); - tries = g_list_append (tries, g_build_filename (debug_file_directory, dir, basename, NULL)); + tries = sp_symbol_dirs_get_paths (dir, basename); - for (list = tries; list != NULL; list = list->next) + for (i = 0; tries[i]; i++) { - const char *name = list->data; + const char *name = tries[i]; ElfParser *parser = elf_parser_new (name, NULL); guint32 file_crc; const char *file_build_id; @@ -220,9 +216,7 @@ get_debuglink_file (ElfParser *elf, } g_free (dir); - - g_list_foreach (tries, (GFunc)g_free, NULL); - g_list_free (tries); + g_strfreev (tries); return result; }