[PATCH resend 2/8] mmap_cache: new subsystem derived from unwind.c

Masatake YAMATO yamato at redhat.com
Fri Feb 16 19:37:09 UTC 2018


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 all mmap cache code in unwind.c
to mmap_cache.c, a new file.

* Makefile.am (mmap_cache.c): New file.
* defs.h (mmap_cache_invalidate): Renamed from unwind_cache_invalidate.
(mmap_cache_delete): Renamed from delete_mmap_cache and extern'ed.
(mmap_cache_rebuild_if_invalid): Renamed from unwind_cache_invalidate
and extern'ed.
(struct mmap_cache_t): Move from unwind.c.
(enum mmap_cache_rebuild_result): Move from unwind.c.
* unwind.c: remove mmap_cache implementation.
* syscall.c: call a function for invalidating mmap cache with new
name.

Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
 Makefile.am  |   1 +
 defs.h       |  31 +++++++++-
 mmap_cache.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 syscall.c    |   2 +-
 unwind.c     | 188 +----------------------------------------------------------
 5 files changed, 220 insertions(+), 187 deletions(-)
 create mode 100644 mmap_cache.c

diff --git a/Makefile.am b/Makefile.am
index db9ad6e8..3f7025f1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 de55d3b7..eb3aee4d 100644
--- a/defs.h
+++ b/defs.h
@@ -716,11 +716,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
index 00000000..eadfe283
--- /dev/null
+++ b/mmap_cache.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013 Luca Clementi <luca.clementi at 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);
+}
diff --git a/syscall.c b/syscall.c
index cb9bce1e..66d91022 100644
--- 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
 
diff --git a/unwind.c b/unwind.c
index c171844c..77fb2378 100644
--- a/unwind.c
+++ b/unwind.c
@@ -26,7 +26,6 @@
  */
 
 #include "defs.h"
-#include <limits.h>
 #include <libunwind-ptrace.h>
 
 #ifdef USE_DEMANGLE
@@ -37,38 +36,6 @@
 # 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 */
-- 
2.14.3





More information about the Strace-devel mailing list