1 /*
2  * Check decoding of move_pages syscall.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016-2018 The strace developers.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "tests.h"
32 #include <asm/unistd.h>
33 
34 #ifdef __NR_move_pages
35 
36 # include <errno.h>
37 # include <stdio.h>
38 # include <unistd.h>
39 
40 # define MAX_STRLEN 3
41 
42 static void
print_page_array(const void ** const pages,const unsigned long count,const unsigned int offset)43 print_page_array(const void **const pages,
44 		 const unsigned long count,
45 		 const unsigned int offset)
46 {
47 	if (!count) {
48 		printf("%s", pages ? "[]" : "NULL");
49 		return;
50 	}
51 	if (count <= offset) {
52 		printf("%p", pages);
53 		return;
54 	}
55 	printf("[");
56 	unsigned long i;
57 	for (i = 0; i < count; ++i) {
58 		if (i)
59 			printf(", ");
60 		if (i + offset < count) {
61 			if (i >= MAX_STRLEN) {
62 				printf("...");
63 				break;
64 			}
65 		} else {
66 			printf("... /* %p */", pages + i);
67 			break;
68 		}
69 		const void *const addr = pages[i];
70 		if (addr)
71 			printf("%p", addr);
72 		else
73 			printf("NULL");
74 	}
75 	printf("]");
76 }
77 
78 static void
print_node_array(const int * const nodes,const unsigned long count,const unsigned int offset)79 print_node_array(const int *const nodes,
80 		 const unsigned long count,
81 		 const unsigned int offset)
82 {
83 	if (!count) {
84 		printf("%s", nodes ? "[]" : "NULL");
85 		return;
86 	}
87 	if (count <= offset) {
88 		printf("%p", nodes);
89 		return;
90 	}
91 	printf("[");
92 	unsigned long i;
93 	for (i = 0; i < count; ++i) {
94 		if (i)
95 			printf(", ");
96 		if (i + offset < count) {
97 			if (i >= MAX_STRLEN) {
98 				printf("...");
99 				break;
100 			}
101 		} else {
102 			printf("... /* %p */", nodes + i);
103 			break;
104 		}
105 		printf("%d", nodes[i]);
106 	}
107 	printf("]");
108 }
109 
110 static void
print_status_array(const int * const status,const unsigned long count)111 print_status_array(const int *const status, const unsigned long count)
112 {
113 	if (!count) {
114 		printf("%s", status ? "[]" : "NULL");
115 		return;
116 	}
117 	printf("[");
118 	unsigned long i;
119 	for (i = 0; i < count; ++i) {
120 		if (i)
121 			printf(", ");
122 		if (i >= MAX_STRLEN) {
123 			printf("...");
124 			break;
125 		}
126 		if (status[i] >= 0) {
127 			printf("%d", status[i]);
128 		} else {
129 			errno = -status[i];
130 			printf("-%s", errno2name());
131 		}
132 	}
133 	printf("]");
134 }
135 
136 static void
print_stat_pages(const unsigned long pid,const unsigned long count,const void ** const pages,int * const status)137 print_stat_pages(const unsigned long pid, const unsigned long count,
138 		 const void **const pages, int *const status)
139 {
140 	const unsigned long flags = (unsigned long) 0xfacefeed00000002ULL;
141 
142 	long rc = syscall(__NR_move_pages,
143 			  pid, count, pages, NULL, status, flags);
144 	const char *errstr = sprintrc(rc);
145 	printf("move_pages(%d, %lu, ", (int) pid, count);
146 	print_page_array(pages, count, 0);
147 	printf(", NULL, ");
148 	if (rc) {
149 		if (count)
150 			printf("%p", status);
151 		else
152 			printf("[]");
153 	} else {
154 		print_status_array(status, count);
155 	}
156 	printf(", MPOL_MF_MOVE) = %s\n", errstr);
157 }
158 
159 static void
print_move_pages(const unsigned long pid,unsigned long count,const unsigned int offset,const void ** const pages,int * const nodes,int * const status)160 print_move_pages(const unsigned long pid,
161 		 unsigned long count,
162 		 const unsigned int offset,
163 		 const void **const pages,
164 		 int *const nodes,
165 		 int *const status)
166 {
167 	const unsigned long flags = (unsigned long) 0xfacefeed00000004ULL;
168 	count += offset;
169 
170 	long rc = syscall(__NR_move_pages,
171 			  pid, count, pages, nodes, status, flags);
172 	const char *errstr = sprintrc(rc);
173 	printf("move_pages(%d, %lu, ", (int) pid, count);
174 	print_page_array(pages, count, offset);
175 	printf(", ");
176 	print_node_array(nodes, count, offset);
177 	printf(", ");
178 	if (count)
179 		printf("%p", status);
180 	else
181 		printf("[]");
182 	printf(", MPOL_MF_MOVE_ALL) = %s\n", errstr);
183 }
184 
185 int
main(void)186 main(void)
187 {
188 	const unsigned long pid =
189 		(unsigned long) 0xfacefeed00000000ULL | getpid();
190 	unsigned long count = 1;
191 	const unsigned page_size = get_page_size();
192 	const void *const page = tail_alloc(page_size);
193 	const void *const efault = page + page_size;
194 	TAIL_ALLOC_OBJECT_VAR_PTR(const void *, pages);
195 	TAIL_ALLOC_OBJECT_VAR_PTR(int, nodes);
196 	TAIL_ALLOC_OBJECT_VAR_PTR(int, status);
197 
198 	print_stat_pages(pid, 0, pages, status);
199 	print_move_pages(pid, 0, 0, pages, nodes, status);
200 	print_move_pages(pid, 0, 1, pages + 1, nodes + 1, status + 1);
201 
202 	*pages = page;
203 	print_stat_pages(pid, count, pages, status);
204 	*nodes = 0xdeadbee1;
205 	print_move_pages(pid, count, 0, pages, nodes, status);
206 	print_move_pages(pid, count, 1, pages, nodes, status);
207 
208 	++count;
209 	--status;
210 	*(--pages) = efault;
211 	print_stat_pages(pid, count, pages, status);
212 	*(--nodes) = 0xdeadbee2;
213 	print_move_pages(pid, count, 0, pages, nodes, status);
214 	print_move_pages(pid, count, 1, pages, nodes, status);
215 
216 	++count;
217 	--status;
218 	*(--pages) = nodes;
219 	print_stat_pages(pid, count, pages, status);
220 	*(--nodes) = 0xdeadbee3;
221 	print_move_pages(pid, count, 0, pages, nodes, status);
222 	print_move_pages(pid, count, 1, pages, nodes, status);
223 
224 	++count;
225 	--status;
226 	*(--pages) = status;
227 	print_stat_pages(pid, count, pages, status);
228 	*(--nodes) = 0xdeadbee4;
229 	print_move_pages(pid, count, 0, pages, nodes, status);
230 	print_move_pages(pid, count, 1, pages, nodes, status);
231 
232 	puts("+++ exited with 0 +++");
233 	return 0;
234 }
235 
236 #else
237 
238 SKIP_MAIN_UNDEFINED("__NR_move_pages")
239 
240 #endif
241