flt.lttng-utils.debug-info: Implement file descriptor cache
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Wed, 3 Apr 2019 17:06:08 +0000 (13:06 -0400)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Thu, 2 May 2019 20:50:15 +0000 (20:50 +0000)
A `flt.lttng-utils.debug-info` component has to open files in order to
do the address resolving when processing a trace. Those file descriptors
are currently associated with a bin_info structure which are stored in a
hash table for each vpid. If, in the same trace, a binary file is loaded
by more than one process, that binary file will be opened twice. This
can create a file descriptor exhaustion problem on long running traces
if the same UST apps are run repeatedly.

This commit implements a file descriptor caching feature to reuse file
descriptors pointing to the same files.

After creating the file descriptor cache (fdcache), users must use the
following two functions to get and put handles to file descriptors:
  struct fd_handle *fd_cache_get_handle(struct fd_cache *fdc, char *path);
  void fd_cache_put_handle(struct fd_cache *fdc, struct fd_handle *handle);

The fd_handles are reference counted internally and their corresponding
file descriptors are closed when the refcount reaches zero.

Files are compared based on the hashed values of inode and device number
rather than solely on the path. This is needed to make sure that a file
opened previously has not changed. This is more likely to happen when
processing a lttng-live trace where the following scenario can happen
and must be supported:
  1. Binary v1 is executed,
  2. Trace data received by debug-info component,
  3. Handle 1 is taken on the bin_a v1 file,
  4. Addresses resolved using handle 1,
  5. Binary is modified,
  6. Binary v2 is compiled,
  7. Binary v2 is executed,
  8. Trace data received by debug-info component,
  9. Handle 2 is taken on the bin_a v2 file,
  10. Addresses resolved using handle 2.

Limitation
----------
It's still be possible to exhaust file descriptors in traces with a
large number of UST apps with no binary file overlap. If this becomes a
problem, we may consider devising an utility to close least recently
used files and reopening file descriptors for later used.

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
14 files changed:
Makefile.am
configure.ac
fd-cache/Makefile.am [new file with mode: 0644]
fd-cache/fd-cache.c [new file with mode: 0644]
fd-cache/logging.c [new file with mode: 0644]
fd-cache/logging.h [new file with mode: 0644]
include/babeltrace/fd-cache-internal.h [new file with mode: 0644]
plugins/lttng-utils/Makefile.am
plugins/lttng-utils/debug-info/Makefile.am
plugins/lttng-utils/debug-info/bin-info.c
plugins/lttng-utils/debug-info/bin-info.h
plugins/lttng-utils/debug-info/debug-info.c
tests/plugins/Makefile.am
tests/plugins/test_bin_info.c

index 76114749790e84f555bae56c326c35dc666d4ed4..341f83533695aa362093071c22394d2ce114109e 100644 (file)
@@ -3,6 +3,7 @@ ACLOCAL_AMFLAGS = -I m4
 SUBDIRS = include              \
        common                  \
        ctfser                  \
+       fd-cache                \
        compat                  \
        logging                 \
        lib
index 45c6548c384f36285e11999d0a2b771946c6b60f..3797984942c82da556f243b8bf05838b31cd60c2 100644 (file)
@@ -737,6 +737,7 @@ AC_CONFIG_FILES([
        doc/contributing-images/Makefile
   doc/man/Makefile
   doc/man/asciidoc-attrs.conf
+       fd-cache/Makefile
        lib/Makefile
        lib/prio_heap/Makefile
        lib/plugin/Makefile
diff --git a/fd-cache/Makefile.am b/fd-cache/Makefile.am
new file mode 100644 (file)
index 0000000..505ef8d
--- /dev/null
@@ -0,0 +1,8 @@
+AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
+
+noinst_LTLIBRARIES = libbabeltrace-fd-cache.la
+
+libbabeltrace_fd_cache_la_SOURCES = \
+       fd-cache.c \
+       logging.c \
+       logging.h
diff --git a/fd-cache/fd-cache.c b/fd-cache/fd-cache.c
new file mode 100644 (file)
index 0000000..5dad8da
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * fd-cache.c
+ *
+ * Babeltrace - File descriptor cache
+ *
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FD-CACHE"
+#include "logging.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/fd-cache-internal.h>
+
+struct file_key {
+       uint64_t dev;
+       uint64_t ino;
+};
+
+struct fd_handle_internal {
+       struct bt_fd_cache_handle fd_handle;
+       uint64_t ref_count;
+       struct file_key *key;
+};
+
+static
+void fd_cache_handle_internal_destroy(
+               struct fd_handle_internal *internal_fd)
+{
+       if (!internal_fd) {
+               goto end;
+       }
+
+       if (internal_fd->fd_handle.fd >= 0) {
+               close(internal_fd->fd_handle.fd);
+               internal_fd->fd_handle.fd = -1;
+       }
+
+end:
+       g_free(internal_fd);
+}
+
+/*
+ * Using simple hash algorithm found on stackoverflow:
+ * https://stackoverflow.com/questions/664014/
+ */
+static inline
+uint64_t hash_uint64_t(uint64_t x) {
+       x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
+       x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
+       x = x ^ (x >> 31);
+       return x;
+}
+
+static
+guint file_key_hash(gconstpointer v)
+{
+       const struct file_key *fk = v;
+       return hash_uint64_t(fk->dev) ^ hash_uint64_t(fk->ino);
+}
+
+static
+gboolean file_key_equal(gconstpointer v1, gconstpointer v2)
+{
+       const struct file_key *fk1 = v1;
+       const struct file_key *fk2 = v2;
+
+       return (fk1->dev == fk2->dev) && (fk1->ino == fk2->ino);
+}
+
+static
+void file_key_destroy(gpointer data)
+{
+       struct file_key *fk = data;
+       g_free(fk);
+}
+
+BT_HIDDEN
+int bt_fd_cache_init(struct bt_fd_cache *fdc)
+{
+       int ret = 0;
+
+       fdc->cache = g_hash_table_new_full(file_key_hash, file_key_equal,
+               file_key_destroy, (GDestroyNotify) fd_cache_handle_internal_destroy);
+       if (!fdc->cache) {
+               ret = -1;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+void bt_fd_cache_fini(struct bt_fd_cache *fdc)
+{
+       BT_ASSERT(fdc->cache);
+       /*
+        * All handle should have been removed for the hashtable at this point.
+        */
+       BT_ASSERT(g_hash_table_size(fdc->cache) == 0);
+       g_hash_table_destroy(fdc->cache);
+
+       return;
+}
+
+BT_HIDDEN
+struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
+               const char *path)
+{
+       struct fd_handle_internal *fd_internal = NULL;
+       struct stat statbuf;
+       struct file_key fk;
+       int ret;
+
+       ret = stat(path, &statbuf);
+       if (ret < 0) {
+               BT_LOGE_ERRNO("Failed to stat file", ": path=%s", path);
+               goto end;
+       }
+
+       /*
+        * Use the device number and inode number to uniquely identify a file.
+        * Even if the file as the same path, it may have been replaced so we
+        * must open a new FD for it. This replacement of file is more likely
+        * to happen with a lttng-live source component.
+        */
+       fk.dev = statbuf.st_dev;
+       fk.ino = statbuf.st_ino;
+
+       fd_internal = g_hash_table_lookup(fdc->cache, &fk);
+       if (!fd_internal) {
+               gboolean ret;
+               struct file_key *file_key;
+
+               int fd = open(path, O_RDONLY);
+               if (fd < 0) {
+                       BT_LOGE_ERRNO("Failed to open file", "path=%s", path);
+                       goto error;
+               }
+
+               fd_internal = g_new0(struct fd_handle_internal, 1);
+               if (!fd_internal) {
+                       BT_LOGE("Failed to allocate fd internal handle");
+                       goto error;
+               }
+
+               file_key = g_new0(struct file_key, 1);
+               if (!fd_internal) {
+                       BT_LOGE("Failed to allocate file key");
+                       goto error;
+               }
+
+               *file_key = fk;
+
+               fd_internal->fd_handle.fd = fd;
+               fd_internal->ref_count = 0;
+               fd_internal->key = file_key;
+
+               /* Insert the newly created fd handle. */
+               ret = g_hash_table_insert(fdc->cache, fd_internal->key,
+                               fd_internal);
+               BT_ASSERT(ret);
+       }
+
+       BT_ASSERT(fd_internal->ref_count >= 0);
+
+       fd_internal->ref_count++;
+       goto end;
+
+error:
+       fd_cache_handle_internal_destroy(fd_internal);
+       fd_internal = NULL;
+end:
+       return (struct bt_fd_cache_handle *) fd_internal;
+}
+
+BT_HIDDEN
+void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
+               struct bt_fd_cache_handle *handle)
+{
+       struct fd_handle_internal *fd_internal;
+
+       if (!handle) {
+               goto end;
+       }
+
+       fd_internal = (struct fd_handle_internal *) handle;
+
+       BT_ASSERT(fd_internal->ref_count > 0);
+
+       if (fd_internal->ref_count > 1) {
+               fd_internal->ref_count--;
+       } else {
+               gboolean ret;
+               int close_ret;
+
+               close_ret = close(fd_internal->fd_handle.fd);
+               if (close_ret == -1) {
+                       BT_LOGW_ERRNO("Failed to close file descriptor",
+                               ": fd=%d", fd_internal->fd_handle.fd);
+               }
+               ret = g_hash_table_remove(fdc->cache, fd_internal->key);
+               BT_ASSERT(ret);
+       }
+
+end:
+       return;
+}
diff --git a/fd-cache/logging.c b/fd-cache/logging.c
new file mode 100644 (file)
index 0000000..cd4029d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_fd_cache_log_level
+#include <babeltrace/logging-internal.h>
+
+BT_LOG_INIT_LOG_LEVEL(bt_fd_cache_log_level, "BABELTRACE_FD_CACHE_LOG_LEVEL");
diff --git a/fd-cache/logging.h b/fd-cache/logging.h
new file mode 100644 (file)
index 0000000..343f3d4
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef FD_CACHE_LOGGING_H
+#define FD_CACHE_LOGGING_H
+
+/*
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_fd_cache_log_level
+#include <babeltrace/logging-internal.h>
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_fd_cache_log_level);
+
+#endif /* FD_CACHE_LOGGING_H */
diff --git a/include/babeltrace/fd-cache-internal.h b/include/babeltrace/fd-cache-internal.h
new file mode 100644 (file)
index 0000000..4a623e0
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef BABELTRACE_FD_CACHE_INTERNAL_H
+#define BABELTRACE_FD_CACHE_INTERNAL_H
+/*
+ * fd-cache-internal.h
+ *
+ * Babeltrace - File descriptor cache
+ *
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/babeltrace-internal.h>
+
+struct bt_fd_cache_handle {
+       int fd;
+};
+
+struct bt_fd_cache {
+       GHashTable *cache;
+};
+
+static inline
+int bt_fd_cache_handle_get_fd(struct bt_fd_cache_handle *handle)
+{
+       return handle->fd;
+}
+
+BT_HIDDEN
+int bt_fd_cache_init(struct bt_fd_cache *fdc);
+
+BT_HIDDEN
+void bt_fd_cache_fini(struct bt_fd_cache *fdc);
+
+BT_HIDDEN
+struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
+               const char *path);
+
+BT_HIDDEN
+void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
+               struct bt_fd_cache_handle *handle);
+
+#endif /* BABELTRACE_FD_CACHE_INTERNAL_H */
index 34ff2a6499e3dcc3a142830690a36cafaa1496a6..969e296e3648a04a1c5d6334992ede1d004eb644 100644 (file)
@@ -1,6 +1,11 @@
 SUBDIRS =
+
+babeltrace_plugin_lttng_utils_la_LIBADD =
+
 if ENABLE_DEBUG_INFO
 SUBDIRS += debug-info
+babeltrace_plugin_lttng_utils_la_LIBADD += \
+       debug-info/libdebug-info.la
 endif
 
 AM_CPPFLAGS += -I$(top_srcdir)/plugins
@@ -11,9 +16,6 @@ plugin_LTLIBRARIES = babeltrace-plugin-lttng-utils.la
 babeltrace_plugin_lttng_utils_la_SOURCES = \
        plugin.c
 
-babeltrace_plugin_lttng_utils_la_LIBADD = \
-       debug-info/libdebug-info.la
-
 babeltrace_plugin_lttng_utils_la_LDFLAGS = \
        $(LT_NO_UNDEFINED) \
        -avoid-version -module \
index f43feac6cf1d68d65b709d2ab57739be87e63d77..e1ff7d7eeedd476421d7e45883d9e6362df29b5f 100644 (file)
@@ -1,6 +1,10 @@
 AM_CPPFLAGS += -I$(top_srcdir)/plugins
 
 noinst_LTLIBRARIES = libdebug-info.la
+
+libdebug_info_la_LIBADD = \
+       $(top_builddir)/fd-cache/libbabeltrace-fd-cache.la
+
 libdebug_info_la_SOURCES = \
        bin-info.c \
        bin-info.h \
index c3e16cec9b97c3ff38ec5c8315f4acc548f27360..dd42f41cfbcd6301dcfef11e25964a4edb7f1447 100644 (file)
 #define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO"
 #include "logging.h"
 
+#include <dwarf.h>
+#include <errno.h>
 #include <fcntl.h>
-#include <math.h>
+#include <inttypes.h>
 #include <libgen.h>
+#include <math.h>
 #include <stdio.h>
-#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <dwarf.h>
+
 #include <glib.h>
-#include <errno.h>
-#include "dwarf.h"
+
 #include "bin-info.h"
 #include "crc32.h"
+#include "dwarf.h"
 #include "utils.h"
 
 /*
@@ -68,12 +70,14 @@ int bin_info_init(void)
 }
 
 BT_HIDDEN
-struct bin_info *bin_info_create(const char *path, uint64_t low_addr,
-               uint64_t memsz, bool is_pic, const char *debug_info_dir,
-               const char *target_prefix)
+struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
+               uint64_t low_addr, uint64_t memsz, bool is_pic,
+               const char *debug_info_dir, const char *target_prefix)
 {
        struct bin_info *bin = NULL;
 
+       BT_ASSERT(fdc);
+
        if (!path) {
                goto error;
        }
@@ -108,6 +112,7 @@ struct bin_info *bin_info_create(const char *path, uint64_t low_addr,
        bin->build_id = NULL;
        bin->build_id_len = 0;
        bin->file_build_id_matches = false;
+       bin->fd_cache = fdc;
 
        return bin;
 
@@ -133,8 +138,8 @@ void bin_info_destroy(struct bin_info *bin)
 
        elf_end(bin->elf_file);
 
-       close(bin->elf_fd);
-       close(bin->dwarf_fd);
+       bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle);
+       bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle);
 
        g_free(bin);
 }
@@ -148,43 +153,39 @@ void bin_info_destroy(struct bin_info *bin)
 static
 int bin_info_set_elf_file(struct bin_info *bin)
 {
-       int elf_fd = -1;
+       struct bt_fd_cache_handle *elf_handle = NULL;
        Elf *elf_file = NULL;
 
        if (!bin) {
                goto error;
        }
 
-       elf_fd = open(bin->elf_path, O_RDONLY);
-       if (elf_fd < 0) {
-               elf_fd = -errno;
-               BT_LOGE("Failed to open %s\n", bin->elf_path);
+       elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path);
+       if (!elf_handle) {
+               BT_LOGD("Failed to open %s", bin->elf_path);
                goto error;
        }
 
-       elf_file = elf_begin(elf_fd, ELF_C_READ, NULL);
+       elf_file = elf_begin(bt_fd_cache_handle_get_fd(elf_handle),
+               ELF_C_READ, NULL);
        if (!elf_file) {
-               BT_LOGE("elf_begin failed: %s\n", elf_errmsg(-1));
+               BT_LOGE("elf_begin failed: %s", elf_errmsg(-1));
                goto error;
        }
 
        if (elf_kind(elf_file) != ELF_K_ELF) {
-               BT_LOGE("Error: %s is not an ELF object\n",
-                               bin->elf_path);
+               BT_LOGE("Error: %s is not an ELF object", bin->elf_path);
                goto error;
        }
 
-       bin->elf_fd = elf_fd;
+       bin->elf_handle = elf_handle;
        bin->elf_file = elf_file;
        return 0;
 
 error:
-       if (elf_fd >= 0) {
-               close(elf_fd);
-               elf_fd = -1;
-       }
+       bt_fd_cache_put_handle(bin->fd_cache, elf_handle);
        elf_end(elf_file);
-       return elf_fd;
+       return -1;
 }
 
 /**
@@ -441,7 +442,8 @@ error:
 static
 int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
 {
-       int fd = -1, ret = 0;
+       int ret = 0;
+       struct bt_fd_cache_handle *dwarf_handle = NULL;
        struct bt_dwarf_cu *cu = NULL;
        Dwarf *dwarf_info = NULL;
 
@@ -449,13 +451,13 @@ int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
                goto error;
        }
 
-       fd = open(path, O_RDONLY);
-       if (fd < 0) {
-               fd = -errno;
+       dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
+       if (!dwarf_handle) {
                goto error;
        }
 
-       dwarf_info = dwarf_begin(fd, DWARF_C_READ);
+       dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle),
+               DWARF_C_READ);
        if (!dwarf_info) {
                goto error;
        }
@@ -474,7 +476,7 @@ int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
                goto error;
        }
 
-       bin->dwarf_fd = fd;
+       bin->dwarf_handle = dwarf_handle;
        bin->dwarf_path = g_strdup(path);
        if (!bin->dwarf_path) {
                goto error;
@@ -485,15 +487,12 @@ int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
        return 0;
 
 error:
-       if (fd >= 0) {
-               close(fd);
-               fd = -1;
-       }
+       bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle);
        dwarf_end(dwarf_info);
        g_free(dwarf_info);
        free(cu);
 
-       return fd;
+       return -1;
 }
 
 /**
@@ -570,21 +569,22 @@ end:
  *             0 otherwise
  */
 static
-int is_valid_debug_file(char *path, uint32_t crc)
+int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc)
 {
-       int ret = 0, fd = -1;
+       int ret = 0;
+       struct bt_fd_cache_handle *debug_handle = NULL;
        uint32_t _crc = 0;
 
        if (!path) {
-               goto end_noclose;
+               goto end;
        }
 
-       fd = open(path, O_RDONLY);
-       if (fd < 0) {
-               goto end_noclose;
+       debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
+       if (!debug_handle) {
+               goto end;
        }
 
-       ret = crc32(fd, &_crc);
+       ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc);
        if (ret) {
                ret = 0;
                goto end;
@@ -593,8 +593,7 @@ int is_valid_debug_file(char *path, uint32_t crc)
        ret = (crc == _crc);
 
 end:
-       close(fd);
-end_noclose:
+       bt_fd_cache_put_handle(bin->fd_cache, debug_handle);
        return ret;
 }
 
@@ -628,7 +627,7 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
        /* First look in the executable's dir */
        path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL);
 
-       if (is_valid_debug_file(path, bin->dbg_link_crc)) {
+       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
                goto found;
        }
 
@@ -636,7 +635,7 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
        g_free(path);
        path = g_strconcat(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL);
 
-       if (is_valid_debug_file(path, bin->dbg_link_crc)) {
+       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
                goto found;
        }
 
@@ -644,7 +643,7 @@ int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
        g_free(path);
 
        path = g_strconcat(dbg_dir, bin_dir, bin->dbg_link_filename, NULL);
-       if (is_valid_debug_file(path, bin->dbg_link_crc)) {
+       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
                goto found;
        }
 
@@ -1101,7 +1100,8 @@ int bin_info_lookup_function_name(struct bin_info *bin,
        if (!bin->dwarf_info && !bin->is_elf_only) {
                ret = bin_info_set_dwarf_info(bin);
                if (ret) {
-                       BT_LOGD_STR("Failed to set bin dwarf info, falling back to ELF lookup.");
+                       BT_LOGD_STR("Failed to set bin dwarf info, falling "
+                                       "back to ELF lookup.");
                        /* Failed to set DWARF info, fallback to ELF. */
                        bin->is_elf_only = true;
                }
index 2bcd9fae42cd55b1896fe41f765300abdb667da6..f6848fb3bae6c7e8ff529b39d94ce172269ab9b9 100644 (file)
@@ -32,6 +32,7 @@
 #include <gelf.h>
 #include <elfutils/libdw.h>
 #include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/fd-cache-internal.h>
 
 #define DEFAULT_DEBUG_DIR "/usr/lib/debug"
 #define DEBUG_SUBDIR ".debug/"
@@ -58,9 +59,9 @@ struct bin_info {
        /* Optional debug link info. */
        gchar *dbg_link_filename;
        uint32_t dbg_link_crc;
-       /* FDs to ELF and DWARF files. */
-       int elf_fd;
-       int dwarf_fd;
+       /* fd cache handles to ELF and DWARF files. */
+       struct bt_fd_cache_handle *elf_handle;
+       struct bt_fd_cache_handle *dwarf_handle;
        /* Configuration. */
        gchar *debug_info_dir;
        /* Denotes whether the executable is position independent code. */
@@ -72,6 +73,8 @@ struct bin_info {
         * DWARF info.
         */
        bool is_elf_only:1;
+       /* Weak ref. Owned by the iterator. */
+       struct bt_fd_cache *fd_cache;
 };
 
 struct source_location {
@@ -104,9 +107,9 @@ int bin_info_init(void);
  *                     NULL on failure.
  */
 BT_HIDDEN
-struct bin_info *bin_info_create(const char *path, uint64_t low_addr,
-               uint64_t memsz, bool is_pic, const char *debug_info_dir,
-               const char *target_prefix);
+struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
+               uint64_t low_addr, uint64_t memsz, bool is_pic,
+               const char *debug_info_dir, const char *target_prefix);
 
 /**
  * Destroy the given bin_info instance
index d84bf397a0af59a82b20202331e614b3008fce05..b2620b6ad08aa9845e4aaf434dfaa592bbd50350 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <babeltrace/assert-internal.h>
 #include <babeltrace/common-internal.h>
+#include <babeltrace/fd-cache-internal.h>
 
 #include "bin-info.h"
 #include "debug-info.h"
@@ -70,6 +71,8 @@ struct debug_info_msg_iter {
        struct trace_ir_maps *ir_maps;
        /* in_trace -> debug_info_mapping. */
        GHashTable *debug_info_map;
+
+       struct bt_fd_cache fd_cache;
 };
 
 struct debug_info_source {
@@ -124,6 +127,7 @@ struct debug_info {
        GQuark q_dl_open;
        GQuark q_lib_load;
        GQuark q_lib_unload;
+       struct bt_fd_cache *fd_cache; /* Weak ref. Owned by the iterator. */
 };
 
 static
@@ -491,7 +495,7 @@ end:
        return debug_info_src;
 }
 
-BT_HIDDEN
+static
 struct debug_info_source *debug_info_query(struct debug_info *debug_info,
                int64_t vpid, uint64_t ip)
 {
@@ -510,13 +514,17 @@ end:
        return dbg_info_src;
 }
 
-BT_HIDDEN
+static
 struct debug_info *debug_info_create(struct debug_info_component *comp,
-               const bt_trace *trace)
+               const bt_trace *trace, struct bt_fd_cache *fdc)
 {
        int ret;
        struct debug_info *debug_info;
 
+       BT_ASSERT(comp);
+       BT_ASSERT(trace);
+       BT_ASSERT(fdc);
+
        debug_info = g_new0(struct debug_info, 1);
        if (!debug_info) {
                goto end;
@@ -536,6 +544,7 @@ struct debug_info *debug_info_create(struct debug_info_component *comp,
        }
 
        debug_info->input_trace = trace;
+       debug_info->fd_cache = fdc;
 
 end:
        return debug_info;
@@ -544,7 +553,7 @@ error:
        return NULL;
 }
 
-BT_HIDDEN
+static
 void debug_info_destroy(struct debug_info *debug_info)
 {
        bt_trace_status status;
@@ -712,7 +721,7 @@ void handle_bin_info_event(struct debug_info *debug_info,
                uint64_t is_pic_field_value;
 
                event_get_payload_unsigned_integer_field_value(event,
-                               IS_PIC_FIELD_NAME, &is_pic_field_value);
+                       IS_PIC_FIELD_NAME, &is_pic_field_value);
                is_pic = is_pic_field_value == 1;
        } else {
                /*
@@ -726,7 +735,7 @@ void handle_bin_info_event(struct debug_info *debug_info,
                VPID_FIELD_NAME, &vpid);
 
        proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-                       debug_info->vpid_to_proc_dbg_info_src, vpid);
+               debug_info->vpid_to_proc_dbg_info_src, vpid);
        if (!proc_dbg_info_src) {
                goto end;
        }
@@ -738,21 +747,19 @@ void handle_bin_info_event(struct debug_info *debug_info,
 
        *((uint64_t *) key) = baddr;
 
-       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
-                       key);
+       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, key);
        if (bin) {
                goto end;
        }
 
-       bin = bin_info_create(path, baddr, memsz, is_pic,
+       bin = bin_info_create(debug_info->fd_cache, path, baddr, memsz, is_pic,
                debug_info->comp->arg_debug_dir,
                debug_info->comp->arg_target_prefix);
        if (!bin) {
                goto end;
        }
 
-       g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info,
-                       key, bin);
+       g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info, key, bin);
        /* Ownership passed to ht. */
        key = NULL;
 
@@ -864,7 +871,7 @@ void handle_event_statedump(struct debug_info_msg_iter *debug_it,
        debug_info = g_hash_table_lookup(debug_it->debug_info_map, trace);
        if (!debug_info) {
                debug_info = debug_info_create(debug_it->debug_info_component,
-                               trace);
+                               trace, &debug_it->fd_cache);
                g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace,
                                debug_info);
                bt_trace_add_destruction_listener(trace,
@@ -1936,6 +1943,7 @@ bt_self_message_iterator_status debug_info_msg_iter_init(
        bt_self_component_port_input_message_iterator *upstream_iterator;
        struct debug_info_msg_iter *debug_info_msg_iter;
        gchar *debug_info_field_name;
+       int ret;
 
        /* Borrow the upstream input port. */
        input_port = bt_self_component_filter_borrow_input_port_by_name(
@@ -1993,6 +2001,16 @@ bt_self_message_iterator_status debug_info_msg_iter_init(
                goto end;
        }
 
+       ret = bt_fd_cache_init(&debug_info_msg_iter->fd_cache);
+       if (ret) {
+               trace_ir_maps_destroy(debug_info_msg_iter->ir_maps);
+               g_hash_table_destroy(debug_info_msg_iter->debug_info_map);
+               g_free(debug_info_msg_iter);
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+
        bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter);
 
        debug_info_msg_iter->input_iterator = self_msg_iter;
@@ -2051,5 +2069,7 @@ void debug_info_msg_iter_finalize(bt_self_message_iterator *it)
        trace_ir_maps_destroy(debug_info_msg_iter->ir_maps);
        g_hash_table_destroy(debug_info_msg_iter->debug_info_map);
 
+       bt_fd_cache_fini(&debug_info_msg_iter->fd_cache);
+
        g_free(debug_info_msg_iter);
 }
index 29891787a9d5f624ec5089f7aef9198c30d0ad9d..ae2e8c702365e70822c11f0400d07ba17746efbf 100644 (file)
@@ -17,6 +17,7 @@ endif # !ENABLE_BUILT_IN_PLUGINS
 if ENABLE_DEBUG_INFO
 test_dwarf_LDADD = \
        $(top_builddir)/plugins/lttng-utils/debug-info/libdebug-info.la \
+       $(top_builddir)/fd-cache/libbabeltrace-fd-cache.la \
        $(top_builddir)/logging/libbabeltrace-logging.la \
        $(top_builddir)/common/libbabeltrace-common.la \
        $(ELFUTILS_LIBS) \
@@ -25,6 +26,7 @@ test_dwarf_SOURCES = test_dwarf.c
 
 test_bin_info_LDADD = \
        $(top_builddir)/plugins/lttng-utils/debug-info/libdebug-info.la \
+       $(top_builddir)/fd-cache/libbabeltrace-fd-cache.la \
        $(top_builddir)/logging/libbabeltrace-logging.la \
        $(top_builddir)/common/libbabeltrace-common.la \
        $(ELFUTILS_LIBS) \
index b32f64fa16632dc951ab6b5499823c27130a40cf..e2988017b28cd5639b96a7d25932f1b430b1e7a6 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
+#include <babeltrace/assert-internal.h>
 #include <lttng-utils/debug-info/bin-info.h>
+
 #include "tap/tap.h"
 
 #define NR_TESTS 36
@@ -56,6 +59,7 @@ void test_bin_info_build_id(const char *data_dir)
        char *func_name = NULL;
        struct bin_info *bin = NULL;
        struct source_location *src_loc = NULL;
+       struct bt_fd_cache fdc;
        uint8_t build_id[BUILD_ID_LEN] = {
                0xcd, 0xd9, 0x8c, 0xdd, 0x87, 0xf7, 0xfe, 0x64, 0xc1, 0x3b,
                0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb
@@ -65,7 +69,9 @@ void test_bin_info_build_id(const char *data_dir)
 
        snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME_BUILD_ID);
 
-       bin = bin_info_create(path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
+       ret = bt_fd_cache_init(&fdc);
+       BT_ASSERT(ret == 0);
+       bin = bin_info_create(&fdc, path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
        ok(bin != NULL, "bin_info_create successful");
 
        /* Test setting build_id */
@@ -97,6 +103,7 @@ void test_bin_info_build_id(const char *data_dir)
        }
 
        bin_info_destroy(bin);
+       bt_fd_cache_fini(&fdc);
 }
 
 static
@@ -109,12 +116,16 @@ void test_bin_info_debug_link(const char *data_dir)
        struct source_location *src_loc = NULL;
        char *dbg_filename = "libhello_debug_link_so.debug";
        uint32_t crc = 0xe55c2b98;
+       struct bt_fd_cache fdc;
 
        diag("bin-info tests - separate DWARF via debug link");
 
        snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME_DEBUG_LINK);
 
-       bin = bin_info_create(path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
+       ret = bt_fd_cache_init(&fdc);
+       BT_ASSERT(ret == 0);
+       bin = bin_info_create(&fdc, path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir,
+                       NULL);
        ok(bin != NULL, "bin_info_create successful");
 
        /* Test setting debug link */
@@ -148,6 +159,7 @@ void test_bin_info_debug_link(const char *data_dir)
        }
 
        bin_info_destroy(bin);
+       bt_fd_cache_fini(&fdc);
 }
 
 static
@@ -158,12 +170,15 @@ void test_bin_info_elf(const char *data_dir)
        char *func_name = NULL;
        struct bin_info *bin = NULL;
        struct source_location *src_loc = NULL;
+       struct bt_fd_cache fdc;
 
        diag("bin-info tests - ELF only");
 
        snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME_ELF);
 
-       bin = bin_info_create(path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
+       ret = bt_fd_cache_init(&fdc);
+       BT_ASSERT(ret == 0);
+       bin = bin_info_create(&fdc, path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
        ok(bin != NULL, "bin_info_create successful");
 
        /* Test function name lookup (with ELF) */
@@ -189,6 +204,7 @@ void test_bin_info_elf(const char *data_dir)
 
        source_location_destroy(src_loc);
        bin_info_destroy(bin);
+       bt_fd_cache_fini(&fdc);
 }
 
 static
@@ -199,12 +215,16 @@ void test_bin_info(const char *data_dir)
        char *func_name = NULL;
        struct bin_info *bin = NULL;
        struct source_location *src_loc = NULL;
+       struct bt_fd_cache fdc;
 
        diag("bin-info tests - DWARF bundled with SO file");
 
+
        snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME);
 
-       bin = bin_info_create(path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
+       ret = bt_fd_cache_init(&fdc);
+       BT_ASSERT(ret == 0);
+       bin = bin_info_create(&fdc, path, SO_LOW_ADDR, SO_MEMSZ, true, data_dir, NULL);
        ok(bin != NULL, "bin_info_create successful");
 
        /* Test bin_info_has_address */
@@ -271,6 +291,7 @@ void test_bin_info(const char *data_dir)
                "bin_info_lookup_source_location - fail on addr not found");
 
        bin_info_destroy(bin);
+       bt_fd_cache_fini(&fdc);
 }
 
 int main(int argc, char **argv)
This page took 0.039498 seconds and 4 git commands to generate.