Blame SOURCES/libhugetlbfs-2.20-tests-linkhuge_rw-function-ptr-may-not-refer-to-text.patch

f1281f
commit 9dbe121e3132630e9094d36c2b0624404b75beea
f1281f
Author: Jan Stancek <jstancek@redhat.com>
f1281f
Date:   Tue Sep 1 15:49:35 2015 +0200
f1281f
f1281f
    tests/linkhuge_rw: function ptr may not refer to .text
f1281f
    
f1281f
    On some ABIs function pointer may not refer to .text section.
f1281f
    For example on powerPC 64-bit ABI, function pointer may refer
f1281f
    to a call stub from .opd section.
f1281f
    
f1281f
    This creates a problem for linkhuge_rw tests which run with
f1281f
    HUGETLB_ELFMAP=R, because test is expecting that address of
f1281f
    function pointer will be backed by huge pages. But because
f1281f
    .opd section is from RW PT_LOAD segment, this doens't happen,
f1281f
    since libhugetlbfs is instructed to map only R segments via
f1281f
    HUGETLB_ELFMAP=R.
f1281f
    
f1281f
    This patch is replacing use of function pointer with address
f1281f
    returned by gcc's __builtin_return_address(), that is called
f1281f
    by the function itself. This should provide an address that
f1281f
    is from an actual code, residing in .text section.
f1281f
    
f1281f
    Signed-off-by: Jan Stancek <jstancek@redhat.com>
f1281f
    Cc: Adam Litke <agl@us.ibm.com>
f1281f
    Cc: Eric B Munson <emunson@mgebm.net>
f1281f
    Cc: Petr Holasek <pholasek@redhat.com>
f1281f
    Signed-off-by: Eric B Munson <emunson@mgebm.net>
f1281f
f1281f
diff --git a/tests/linkhuge_rw.c b/tests/linkhuge_rw.c
f1281f
index f58fff2..c1c2e96 100644
f1281f
--- a/tests/linkhuge_rw.c
f1281f
+++ b/tests/linkhuge_rw.c
f1281f
@@ -31,7 +31,8 @@
f1281f
 #include "hugetests.h"
f1281f
 
f1281f
 #define BLOCK_SIZE	16384
f1281f
-#define CONST	0xdeadbeef
f1281f
+#define CONST		0xdeadbeef
f1281f
+#define RETURN_ADDRESS	0x0
f1281f
 
f1281f
 #define BIG_INIT	{ \
f1281f
 	[0] = CONST, [17] = CONST, [BLOCK_SIZE-1] = CONST, \
f1281f
@@ -45,13 +46,49 @@ static int big_bss[BLOCK_SIZE];
f1281f
 const int small_const = CONST;
f1281f
 const int big_const[BLOCK_SIZE] = BIG_INIT;
f1281f
 
f1281f
-static int static_func(int x)
f1281f
+/*
f1281f
+ * Turn function pointer into address from .text.
f1281f
+ *
f1281f
+ * On some ABIs function pointer may not refer to .text section. For example
f1281f
+ * on powerPC 64-bit ABI, function pointer may refer to call stub from
f1281f
+ * .opd section.
f1281f
+ *
f1281f
+ * This function expects that parameter data is a function pointer of type:
f1281f
+ * long f(long), and when called with special parameter, it returns an address
f1281f
+ * corresponding to actual code of the function. Current implementation relies
f1281f
+ * on gcc's __builtin_return_address, see get_pc() below.
f1281f
+ */
f1281f
+static inline void *get_text_addr(void *data)
f1281f
+{
f1281f
+	long (*gettext)(long) = data;
f1281f
+
f1281f
+	return (void *)gettext(RETURN_ADDRESS);
f1281f
+}
f1281f
+
f1281f
+static void __attribute__ ((noinline)) *get_pc(void)
f1281f
+{
f1281f
+#if defined(__s390__) && __WORDSIZE == 32
f1281f
+	/* taken from sysdeps/unix/sysv/linux/s390/s390-32/profil-counter.h
f1281f
+	 * 31-bit s390 pointers don't use the 32th bit, however integers do,
f1281f
+	 * so wrap the value around at 31 bits */
f1281f
+	return (void *)
f1281f
+		((unsigned long) __builtin_return_address(0) & 0x7fffffffUL);
f1281f
+#else
f1281f
+	return __builtin_return_address(0);
f1281f
+#endif
f1281f
+}
f1281f
+
f1281f
+static long static_func(long x)
f1281f
 {
f1281f
+	if (x == RETURN_ADDRESS)
f1281f
+		return (long)get_pc();
f1281f
 	return x;
f1281f
 }
f1281f
 
f1281f
-int global_func(int x)
f1281f
+long global_func(long x)
f1281f
 {
f1281f
+	if (x == RETURN_ADDRESS)
f1281f
+		return (long)get_pc();
f1281f
 	return x;
f1281f
 }
f1281f
 
f1281f
@@ -59,27 +96,28 @@ static struct test_entry {
f1281f
 	const char *name;
f1281f
 	void *data;
f1281f
 	int size;
f1281f
-	int writable, execable;
f1281f
+	int writable;
f1281f
+	int execable;
f1281f
 	int is_huge;
f1281f
 } testtab[] = {
f1281f
-#define ENT(name, exec)	{ #name, (void *)&name, sizeof(name), 0, exec, }
f1281f
+#define ENT(entry_name, exec) { \
f1281f
+	.name = #entry_name, \
f1281f
+	.data = (void *)&entry_name, \
f1281f
+	.size = sizeof(entry_name), \
f1281f
+	.writable = 0, \
f1281f
+	.execable = exec }
f1281f
+
f1281f
 	ENT(small_data, 0),
f1281f
 	ENT(big_data, 0),
f1281f
 	ENT(small_bss, 0),
f1281f
 	ENT(big_bss, 0),
f1281f
 	ENT(small_const, 0),
f1281f
 	ENT(big_const, 0),
f1281f
-
f1281f
-	/*
f1281f
-	 * XXX: Due to the way functions are defined in the powerPC 64-bit ABI,
f1281f
-	 * the following entries will point to a call stub in the data segment
f1281f
-	 * instead of to the code as one might think.  Therefore, test coverage
f1281f
-	 * is not quite as good as it could be for ppc64.
f1281f
-	 */
f1281f
 	ENT(static_func, 1),
f1281f
 	ENT(global_func, 1),
f1281f
 };
f1281f
 
f1281f
+
f1281f
 #define NUM_TESTS	(sizeof(testtab) / sizeof(testtab[0]))
f1281f
 
f1281f
 static
f1281f
@@ -116,12 +154,18 @@ static void check_if_writable(struct test_entry *te)
f1281f
 {
f1281f
 	int pid, ret, status;
f1281f
 
f1281f
-
f1281f
 	pid = fork();
f1281f
 	if (pid < 0)
f1281f
 		FAIL("fork: %s", strerror(errno));
f1281f
 	else if (pid == 0) {
f1281f
-		(*(char *) te->data) = 0;
f1281f
+		void *data;
f1281f
+
f1281f
+		if (te->execable)
f1281f
+			data = get_text_addr(te->data);
f1281f
+		else
f1281f
+			data = te->data;
f1281f
+
f1281f
+		(*(char *)data) = 0;
f1281f
 		exit (0);
f1281f
 	} else {
f1281f
 		ret = waitpid(pid, &status, 0);
f1281f
@@ -137,11 +181,15 @@ static void check_if_writable(struct test_entry *te)
f1281f
 static void do_test(struct test_entry *te)
f1281f
 {
f1281f
 	int i;
f1281f
-	volatile int *p = te->data;
f1281f
+	void *data = te->data;
f1281f
 
f1281f
 	check_if_writable(te);
f1281f
+	verbose_printf("entry: %s, data: %p, writable: %d\n",
f1281f
+		te->name, data, te->writable);
f1281f
 
f1281f
 	if (te->writable) {
f1281f
+		volatile int *p = data;
f1281f
+
f1281f
 		for (i = 0; i < (te->size / sizeof(*p)); i++)
f1281f
 			p[i] = CONST ^ i;
f1281f
 
f1281f
@@ -151,17 +199,23 @@ static void do_test(struct test_entry *te)
f1281f
 			if (p[i] != (CONST ^ i))
f1281f
 				FAIL("mismatch on %s", te->name);
f1281f
 	} else if (te->execable) {
f1281f
-		int (*pf)(int) = te->data;
f1281f
+		long (*pf)(long) = data;
f1281f
+
f1281f
+		data = get_text_addr(data);
f1281f
 
f1281f
 		if ((*pf)(CONST) != CONST)
f1281f
 			FAIL("%s returns incorrect results", te->name);
f1281f
 	} else {
f1281f
 		/* Otherwise just read touch it */
f1281f
+		volatile int *p = data;
f1281f
+
f1281f
 		for (i = 0; i < (te->size / sizeof(*p)); i++)
f1281f
 			p[i];
f1281f
 	}
f1281f
 
f1281f
-	te->is_huge = (test_addr_huge(te->data) == 1);
f1281f
+	te->is_huge = (test_addr_huge(data) == 1);
f1281f
+	verbose_printf("entry: %s, data: %p, is_huge: %d\n",
f1281f
+		te->name, data, te->is_huge);
f1281f
 }
f1281f
 
f1281f
 int main(int argc, char *argv[])