]> granicus.if.org Git - strace/commitdiff
mmap_cache: new subsystem derived from unwind.c
authorMasatake YAMATO <yamato@redhat.com>
Fri, 16 Feb 2018 19:37:09 +0000 (04:37 +0900)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 26 Feb 2018 23:22:24 +0000 (23:22 +0000)
For making mmap cache code reusable from other areas in strace than
unwind, mmap cache related code and unwind related code should be
separated.

This change moves the most of mmap cache code from unwind.c
to mmap_cache.c, a new file.

* unwind.c: Move mmap_cache implementation ...
* mmap_cache.c: ... to this new file.
* Makefile.am (strace_SOURCES): add mmap_cache.c.
* defs.h (struct tcb): Move mmap_cache, mmap_cache_size, and
mmap_cache_generation fields out of [USE_LIBUNWIND] condition.
(mmap_cache_invalidate, mmap_cache_delete,
mmap_cache_rebuild_if_invalid): New function prototypes.
(struct mmap_cache_t, enum mmap_cache_rebuild_result): Move from
unwind.c.
* syscall.c (syscall_exiting_decode): Replace unwind_cache_invalidate
with mmap_cache_invalidate.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
Makefile.am
defs.h
mmap_cache.c [new file with mode: 0644]
syscall.c
unwind.c

index db9ad6e8143d8d58e4b77643b183135518f98deb..3f7025f13bf4bf91c3c5245a97e59b2981d4b8ca 100644 (file)
@@ -185,6 +185,7 @@ strace_SOURCES =    \
        membarrier.c    \
        memfd_create.c  \
        mknod.c         \
+       mmap_cache.c    \
        mmsghdr.c       \
        mount.c         \
        mpers_type.h    \
diff --git a/defs.h b/defs.h
index de55d3b7b83fa09a669541d254af42c096f4f8b7..403b20aa1e42a191d75704f1e599f00b36adc369 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -217,11 +217,12 @@ struct tcb {
        struct timeval dtime;   /* Delta for system time usage */
        struct timeval etime;   /* Syscall entry time */
 
-#ifdef USE_LIBUNWIND
-       struct UPT_info *libunwind_ui;
        struct mmap_cache_t *mmap_cache;
        unsigned int mmap_cache_size;
        unsigned int mmap_cache_generation;
+
+#ifdef USE_LIBUNWIND
+       struct UPT_info *libunwind_ui;
        struct queue_t *queue;
 #endif
 };
@@ -716,11 +717,40 @@ extern void tv_div(struct timeval *, const struct timeval *, int);
 extern void unwind_init(void);
 extern void unwind_tcb_init(struct tcb *);
 extern void unwind_tcb_fin(struct tcb *);
-extern void unwind_cache_invalidate(struct tcb *);
 extern void unwind_print_stacktrace(struct tcb *);
 extern void unwind_capture_stacktrace(struct tcb *);
 #endif
 
+/*
+ * Keep a sorted array of cache entries,
+ * so that we can binary search through it.
+ */
+struct mmap_cache_t {
+       /**
+        * example entry:
+        * 7fabbb09b000-7fabbb09f000 r-xp 00179000 fc:00 1180246 /lib/libc-2.11.1.so
+        *
+        * start_addr  is 0x7fabbb09b000
+        * end_addr    is 0x7fabbb09f000
+        * mmap_offset is 0x179000
+        * binary_filename is "/lib/libc-2.11.1.so"
+        */
+       unsigned long start_addr;
+       unsigned long end_addr;
+       unsigned long mmap_offset;
+       char *binary_filename;
+};
+
+enum mmap_cache_rebuild_result {
+       MMAP_CACHE_REBUILD_NOCACHE,
+       MMAP_CACHE_REBUILD_READY,
+       MMAP_CACHE_REBUILD_RENEWED,
+};
+
+extern void mmap_cache_invalidate(struct tcb *tcp);
+extern void mmap_cache_delete(struct tcb *tcp, const char *caller);
+extern enum mmap_cache_rebuild_result mmap_cache_rebuild_if_invalid(struct tcb *tcp, const char *caller);
+
 static inline int
 printstrn(struct tcb *tcp, kernel_ulong_t addr, kernel_ulong_t len)
 {
diff --git a/mmap_cache.c b/mmap_cache.c
new file mode 100644 (file)
index 0000000..eadfe28
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013 Luca Clementi <luca.clementi@gmail.com>
+ * Copyright (c) 2013-2018 The strace developers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+#include <limits.h>
+
+#include "xstring.h"
+
+#ifdef _LARGEFILE64_SOURCE
+# ifdef HAVE_FOPEN64
+#  define fopen_for_input fopen64
+# else
+#  define fopen_for_input fopen
+# endif
+#else
+# define fopen_for_input fopen
+#endif
+
+static unsigned int mmap_cache_generation;
+
+/*
+ * caching of /proc/ID/maps for each process to speed up stack tracing
+ *
+ * The cache must be refreshed after syscalls that affect memory mappings,
+ * e.g. mmap, mprotect, munmap, execve.
+ */
+static void
+build_mmap_cache(struct tcb *tcp)
+{
+       FILE *fp;
+       struct mmap_cache_t *cache_head = NULL;
+       /* start with a small dynamically-allocated array and then expand it */
+       size_t cur_array_size = 0;
+       char filename[sizeof("/proc/4294967296/maps")];
+       char buffer[PATH_MAX + 80];
+
+       xsprintf(filename, "/proc/%u/maps", tcp->pid);
+       fp = fopen_for_input(filename, "r");
+       if (!fp) {
+               perror_msg("fopen: %s", filename);
+               return;
+       }
+
+       while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+               struct mmap_cache_t *entry;
+               unsigned long start_addr, end_addr, mmap_offset;
+               char exec_bit;
+               char binary_path[sizeof(buffer)];
+
+               if (sscanf(buffer, "%lx-%lx %*c%*c%c%*c %lx %*x:%*x %*d %[^\n]",
+                          &start_addr, &end_addr, &exec_bit,
+                          &mmap_offset, binary_path) != 5)
+                       continue;
+
+               /* ignore mappings that have no PROT_EXEC bit set */
+               if (exec_bit != 'x')
+                       continue;
+
+               if (end_addr < start_addr) {
+                       error_msg("%s: unrecognized file format", filename);
+                       break;
+               }
+
+               /*
+                * sanity check to make sure that we're storing
+                * non-overlapping regions in ascending order
+                */
+               if (tcp->mmap_cache_size > 0) {
+                       entry = &cache_head[tcp->mmap_cache_size - 1];
+                       if (entry->start_addr == start_addr &&
+                           entry->end_addr == end_addr) {
+                               /* duplicate entry, e.g. [vsyscall] */
+                               continue;
+                       }
+                       if (start_addr <= entry->start_addr ||
+                           start_addr < entry->end_addr) {
+                               debug_msg("%s: overlapping memory region: "
+                                         "\"%s\" [%08lx-%08lx] overlaps with "
+                                         "\"%s\" [%08lx-%08lx]",
+                                         filename, binary_path, start_addr,
+                                         end_addr, entry->binary_filename,
+                                         entry->start_addr, entry->end_addr);
+                               continue;
+                       }
+               }
+
+               if (tcp->mmap_cache_size >= cur_array_size)
+                       cache_head = xgrowarray(cache_head, &cur_array_size,
+                                               sizeof(*cache_head));
+
+               entry = &cache_head[tcp->mmap_cache_size];
+               entry->start_addr = start_addr;
+               entry->end_addr = end_addr;
+               entry->mmap_offset = mmap_offset;
+               entry->binary_filename = xstrdup(binary_path);
+               tcp->mmap_cache_size++;
+       }
+       fclose(fp);
+       tcp->mmap_cache = cache_head;
+       tcp->mmap_cache_generation = mmap_cache_generation;
+
+       debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p",
+                      tcp->mmap_cache_generation,
+                      mmap_cache_generation,
+                      tcp, tcp->mmap_cache);
+}
+
+/* deleting the cache */
+extern void
+mmap_cache_delete(struct tcb *tcp, const char *caller)
+{
+       unsigned int i;
+
+       debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s",
+                      tcp->mmap_cache_generation,
+                      mmap_cache_generation,
+                      tcp, tcp->mmap_cache, caller);
+
+       for (i = 0; i < tcp->mmap_cache_size; i++) {
+               free(tcp->mmap_cache[i].binary_filename);
+               tcp->mmap_cache[i].binary_filename = NULL;
+       }
+       free(tcp->mmap_cache);
+       tcp->mmap_cache = NULL;
+       tcp->mmap_cache_size = 0;
+}
+
+extern enum mmap_cache_rebuild_result
+mmap_cache_rebuild_if_invalid(struct tcb *tcp, const char *caller)
+{
+       enum mmap_cache_rebuild_result r = MMAP_CACHE_REBUILD_READY;
+       if ((tcp->mmap_cache_generation != mmap_cache_generation)
+           && tcp->mmap_cache)
+               mmap_cache_delete(tcp, caller);
+
+       if (!tcp->mmap_cache) {
+               r = MMAP_CACHE_REBUILD_RENEWED;
+               build_mmap_cache(tcp);
+       }
+
+       if (!(tcp->mmap_cache && tcp->mmap_cache_size))
+               r = MMAP_CACHE_REBUILD_NOCACHE;
+
+       return r;
+}
+
+void
+mmap_cache_invalidate(struct tcb *tcp)
+{
+#if SUPPORTED_PERSONALITIES > 1
+       if (tcp->currpers != DEFAULT_PERSONALITY) {
+               /* disable stack trace */
+               return;
+       }
+#endif
+       mmap_cache_generation++;
+       debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p",
+                      tcp->mmap_cache_generation,
+                      mmap_cache_generation,
+                      tcp, tcp->mmap_cache);
+}
index cb9bce1e51aa1b634aab3e9f7ac6f0df2a501d75..66d91022d92e229f5b04760f738ea2e765ac888d 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -731,7 +731,7 @@ syscall_exiting_decode(struct tcb *tcp, struct timeval *ptv)
 #ifdef USE_LIBUNWIND
        if (stack_trace_enabled) {
                if (tcp->s_ent->sys_flags & STACKTRACE_INVALIDATE_CACHE)
-                       unwind_cache_invalidate(tcp);
+                       mmap_cache_invalidate(tcp);
        }
 #endif
 
index c171844c37ea4b4ba16730c11889ed28648addb9..77fb23780cc58dda4d2c94d70ae17a8c2f2ad54a 100644 (file)
--- a/unwind.c
+++ b/unwind.c
@@ -26,7 +26,6 @@
  */
 
 #include "defs.h"
-#include <limits.h>
 #include <libunwind-ptrace.h>
 
 #ifdef USE_DEMANGLE
 # endif
 #endif
 
-#include "xstring.h"
-
-#ifdef _LARGEFILE64_SOURCE
-# ifdef HAVE_FOPEN64
-#  define fopen_for_input fopen64
-# else
-#  define fopen_for_input fopen
-# endif
-#else
-# define fopen_for_input fopen
-#endif
-
-/*
- * Keep a sorted array of cache entries,
- * so that we can binary search through it.
- */
-struct mmap_cache_t {
-       /**
-        * example entry:
-        * 7fabbb09b000-7fabbb09f000 r-xp 00179000 fc:00 1180246 /lib/libc-2.11.1.so
-        *
-        * start_addr  is 0x7fabbb09b000
-        * end_addr    is 0x7fabbb09f000
-        * mmap_offset is 0x179000
-        * binary_filename is "/lib/libc-2.11.1.so"
-        */
-       unsigned long start_addr;
-       unsigned long end_addr;
-       unsigned long mmap_offset;
-       char *binary_filename;
-};
-
 /*
  * Type used in stacktrace walker
  */
@@ -95,10 +62,8 @@ struct queue_t {
 };
 
 static void queue_print(struct queue_t *queue);
-static void delete_mmap_cache(struct tcb *tcp, const char *caller);
 
 static unw_addr_space_t libunwind_as;
-static unsigned int mmap_cache_generation;
 
 static const char asprintf_error_str[] = "???";
 
@@ -133,159 +98,12 @@ unwind_tcb_fin(struct tcb *tcp)
        free(tcp->queue);
        tcp->queue = NULL;
 
-       delete_mmap_cache(tcp, __func__);
+       mmap_cache_delete(tcp, __func__);
 
        _UPT_destroy(tcp->libunwind_ui);
        tcp->libunwind_ui = NULL;
 }
 
-/*
- * caching of /proc/ID/maps for each process to speed up stack tracing
- *
- * The cache must be refreshed after syscalls that affect memory mappings,
- * e.g. mmap, mprotect, munmap, execve.
- */
-static void
-build_mmap_cache(struct tcb *tcp)
-{
-       FILE *fp;
-       struct mmap_cache_t *cache_head = NULL;
-       size_t cur_array_size = 0;
-       char filename[sizeof("/proc/4294967296/maps")];
-       char buffer[PATH_MAX + 80];
-
-       xsprintf(filename, "/proc/%u/maps", tcp->pid);
-       fp = fopen_for_input(filename, "r");
-       if (!fp) {
-               perror_msg("fopen: %s", filename);
-               return;
-       }
-
-       while (fgets(buffer, sizeof(buffer), fp) != NULL) {
-               struct mmap_cache_t *entry;
-               unsigned long start_addr, end_addr, mmap_offset;
-               char exec_bit;
-               char binary_path[sizeof(buffer)];
-
-               if (sscanf(buffer, "%lx-%lx %*c%*c%c%*c %lx %*x:%*x %*d %[^\n]",
-                          &start_addr, &end_addr, &exec_bit,
-                          &mmap_offset, binary_path) != 5)
-                       continue;
-
-               /* ignore mappings that have no PROT_EXEC bit set */
-               if (exec_bit != 'x')
-                       continue;
-
-               if (end_addr < start_addr) {
-                       error_msg("%s: unrecognized file format", filename);
-                       break;
-               }
-
-               /*
-                * sanity check to make sure that we're storing
-                * non-overlapping regions in ascending order
-                */
-               if (tcp->mmap_cache_size > 0) {
-                       entry = &cache_head[tcp->mmap_cache_size - 1];
-                       if (entry->start_addr == start_addr &&
-                           entry->end_addr == end_addr) {
-                               /* duplicate entry, e.g. [vsyscall] */
-                               continue;
-                       }
-                       if (start_addr <= entry->start_addr ||
-                           start_addr < entry->end_addr) {
-                               debug_msg("%s: overlapping memory region: "
-                                         "\"%s\" [%08lx-%08lx] overlaps with "
-                                         "\"%s\" [%08lx-%08lx]",
-                                         filename, binary_path, start_addr,
-                                         end_addr, entry->binary_filename,
-                                         entry->start_addr, entry->end_addr);
-                               continue;
-                       }
-               }
-
-               if (tcp->mmap_cache_size >= cur_array_size)
-                       cache_head = xgrowarray(cache_head, &cur_array_size,
-                                               sizeof(*cache_head));
-
-               entry = &cache_head[tcp->mmap_cache_size];
-               entry->start_addr = start_addr;
-               entry->end_addr = end_addr;
-               entry->mmap_offset = mmap_offset;
-               entry->binary_filename = xstrdup(binary_path);
-               tcp->mmap_cache_size++;
-       }
-       fclose(fp);
-       tcp->mmap_cache = cache_head;
-       tcp->mmap_cache_generation = mmap_cache_generation;
-
-       debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p",
-                      tcp->mmap_cache_generation,
-                      mmap_cache_generation,
-                      tcp, tcp->mmap_cache);
-}
-
-/* deleting the cache */
-static void
-delete_mmap_cache(struct tcb *tcp, const char *caller)
-{
-       unsigned int i;
-
-       debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s",
-                      tcp->mmap_cache_generation,
-                      mmap_cache_generation,
-                      tcp, tcp->mmap_cache, caller);
-
-       for (i = 0; i < tcp->mmap_cache_size; i++) {
-               free(tcp->mmap_cache[i].binary_filename);
-               tcp->mmap_cache[i].binary_filename = NULL;
-       }
-       free(tcp->mmap_cache);
-       tcp->mmap_cache = NULL;
-       tcp->mmap_cache_size = 0;
-}
-
-enum mmap_cache_rebuild_result {
-       MMAP_CACHE_REBUILD_NOCACHE,
-       MMAP_CACHE_REBUILD_READY,
-       MMAP_CACHE_REBUILD_RENEWED,
-};
-
-static enum mmap_cache_rebuild_result
-rebuild_cache_if_invalid(struct tcb *tcp, const char *caller)
-{
-       enum mmap_cache_rebuild_result r = MMAP_CACHE_REBUILD_READY;
-       if ((tcp->mmap_cache_generation != mmap_cache_generation)
-           && tcp->mmap_cache)
-               delete_mmap_cache(tcp, caller);
-
-       if (!tcp->mmap_cache) {
-               r = MMAP_CACHE_REBUILD_RENEWED;
-               build_mmap_cache(tcp);
-       }
-
-       if (!(tcp->mmap_cache && tcp->mmap_cache_size))
-               r = MMAP_CACHE_REBUILD_NOCACHE;
-
-       return r;
-}
-
-void
-unwind_cache_invalidate(struct tcb *tcp)
-{
-#if SUPPORTED_PERSONALITIES > 1
-       if (tcp->currpers != DEFAULT_PERSONALITY) {
-               /* disable stack trace */
-               return;
-       }
-#endif
-       mmap_cache_generation++;
-       debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p",
-                      tcp->mmap_cache_generation,
-                      mmap_cache_generation,
-                      tcp, tcp->mmap_cache);
-}
-
 static void
 get_symbol_name(unw_cursor_t *cursor, char **name,
                size_t *size, unw_word_t *offset)
@@ -588,7 +406,7 @@ unwind_print_stacktrace(struct tcb *tcp)
        if (tcp->queue->head) {
                debug_func_msg("head: tcp=%p, queue=%p", tcp, tcp->queue->head);
                queue_print(tcp->queue);
-       } else switch (rebuild_cache_if_invalid(tcp, __func__)) {
+       } else switch (mmap_cache_rebuild_if_invalid(tcp, __func__)) {
                case MMAP_CACHE_REBUILD_RENEWED:
                        unw_flush_cache(libunwind_as, 0, 0);
                        /* Fall through */
@@ -617,7 +435,7 @@ unwind_capture_stacktrace(struct tcb *tcp)
        if (tcp->queue->head)
                error_msg_and_die("bug: unprinted entries in queue");
 
-       switch (rebuild_cache_if_invalid(tcp, __func__)) {
+       switch (mmap_cache_rebuild_if_invalid(tcp, __func__)) {
        case MMAP_CACHE_REBUILD_RENEWED:
                unw_flush_cache(libunwind_as, 0, 0);
                /* Fall through */