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

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