1/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 2000 PocketPenguins Inc.  Linux for Hitachi SuperH
7 *                    port by Greg Banks <gbanks@pocketpenguins.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include "defs.h"
34#include <asm/mman.h>
35#include <sys/mman.h>
36
37unsigned long
38get_pagesize(void)
39{
40	static unsigned long pagesize;
41
42	if (!pagesize)
43		pagesize = sysconf(_SC_PAGESIZE);
44	return pagesize;
45}
46
47SYS_FUNC(brk)
48{
49	printaddr(tcp->u_arg[0]);
50
51	return RVAL_DECODED | RVAL_HEX;
52}
53
54#include "xlat/mmap_prot.h"
55#include "xlat/mmap_flags.h"
56
57static void
58print_mmap(struct tcb *tcp, long *u_arg, unsigned long long offset)
59{
60	/* addr */
61	printaddr(u_arg[0]);
62	/* len */
63	tprintf(", %lu, ", u_arg[1]);
64	/* prot */
65	printflags(mmap_prot, u_arg[2], "PROT_???");
66	tprints(", ");
67	/* flags */
68#ifdef MAP_TYPE
69	printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
70	addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
71#else
72	printflags(mmap_flags, u_arg[3], "MAP_???");
73#endif
74	tprints(", ");
75	/* fd */
76	printfd(tcp, u_arg[4]);
77	/* offset */
78	tprintf(", %#llx", offset);
79}
80
81/* Syscall name<->function correspondence is messed up on many arches.
82 * For example:
83 * i386 has __NR_mmap == 90, and it is "old mmap", and
84 * also it has __NR_mmap2 == 192, which is a "new mmap with page offsets".
85 * But x86_64 has just one __NR_mmap == 9, a "new mmap with byte offsets".
86 * Confused? Me too!
87 */
88
89/* Params are pointed to by u_arg[0], offset is in bytes */
90SYS_FUNC(old_mmap)
91{
92	long u_arg[6];
93#if defined(IA64)
94	/*
95	 * IA64 processes never call this routine, they only use the
96	 * new 'sys_mmap' interface. Only IA32 processes come here.
97	 */
98	int i;
99	unsigned narrow_arg[6];
100	if (umoven(tcp, tcp->u_arg[0], sizeof(narrow_arg), narrow_arg) == -1)
101		return 0;
102	for (i = 0; i < 6; i++)
103		u_arg[i] = (unsigned long) narrow_arg[i];
104#elif defined(X86_64)
105	/* We are here only in personality 1 (i386) */
106	int i;
107	unsigned narrow_arg[6];
108	if (umoven(tcp, tcp->u_arg[0], sizeof(narrow_arg), narrow_arg) == -1)
109		return 0;
110	for (i = 0; i < 6; ++i)
111		u_arg[i] = (unsigned long) narrow_arg[i];
112#else
113	if (umoven(tcp, tcp->u_arg[0], sizeof(u_arg), u_arg) == -1)
114		return 0;
115#endif
116	print_mmap(tcp, u_arg, (unsigned long) u_arg[5]);
117
118	return RVAL_DECODED | RVAL_HEX;
119}
120
121#if defined(S390)
122/* Params are pointed to by u_arg[0], offset is in pages */
123SYS_FUNC(old_mmap_pgoff)
124{
125	long u_arg[5];
126	int i;
127	unsigned narrow_arg[6];
128	unsigned long long offset;
129	if (umoven(tcp, tcp->u_arg[0], sizeof(narrow_arg), narrow_arg) == -1)
130		return 0;
131	for (i = 0; i < 5; i++)
132		u_arg[i] = (unsigned long) narrow_arg[i];
133	offset = narrow_arg[5];
134	offset *= get_pagesize();
135	print_mmap(tcp, u_arg, offset);
136
137	return RVAL_DECODED | RVAL_HEX;
138}
139#endif
140
141/* Params are passed directly, offset is in bytes */
142SYS_FUNC(mmap)
143{
144	unsigned long long offset = (unsigned long) tcp->u_arg[5];
145#if defined(LINUX_MIPSN32) || defined(X32)
146	/* Try test/x32_mmap.c */
147	offset = tcp->ext_arg[5];
148#endif
149	/* Example of kernel-side handling of this variety of mmap:
150	 * arch/x86/kernel/sys_x86_64.c::SYSCALL_DEFINE6(mmap, ...) calls
151	 * sys_mmap_pgoff(..., off >> PAGE_SHIFT); i.e. off is in bytes,
152	 * since the above code converts off to pages.
153	 */
154	print_mmap(tcp, tcp->u_arg, offset);
155
156	return RVAL_DECODED | RVAL_HEX;
157}
158
159/* Params are passed directly, offset is in pages */
160SYS_FUNC(mmap_pgoff)
161{
162	/* Try test/mmap_offset_decode.c */
163	unsigned long long offset;
164	offset = (unsigned long) tcp->u_arg[5];
165	offset *= get_pagesize();
166	print_mmap(tcp, tcp->u_arg, offset);
167
168	return RVAL_DECODED | RVAL_HEX;
169}
170
171/* Params are passed directly, offset is in 4k units */
172SYS_FUNC(mmap_4koff)
173{
174	unsigned long long offset;
175	offset = (unsigned long) tcp->u_arg[5];
176	offset <<= 12;
177	print_mmap(tcp, tcp->u_arg, offset);
178
179	return RVAL_DECODED | RVAL_HEX;
180}
181
182SYS_FUNC(munmap)
183{
184	printaddr(tcp->u_arg[0]);
185	tprintf(", %lu", tcp->u_arg[1]);
186
187	return RVAL_DECODED;
188}
189
190SYS_FUNC(mprotect)
191{
192	printaddr(tcp->u_arg[0]);
193	tprintf(", %lu, ", tcp->u_arg[1]);
194	printflags(mmap_prot, tcp->u_arg[2], "PROT_???");
195
196	return RVAL_DECODED;
197}
198
199#include "xlat/mremap_flags.h"
200
201SYS_FUNC(mremap)
202{
203	printaddr(tcp->u_arg[0]);
204	tprintf(", %lu, %lu, ", tcp->u_arg[1], tcp->u_arg[2]);
205	printflags(mremap_flags, tcp->u_arg[3], "MREMAP_???");
206#ifdef MREMAP_FIXED
207	if ((tcp->u_arg[3] & (MREMAP_MAYMOVE | MREMAP_FIXED)) ==
208	    (MREMAP_MAYMOVE | MREMAP_FIXED)) {
209		tprints(", ");
210		printaddr(tcp->u_arg[4]);
211	}
212#endif
213	return RVAL_DECODED | RVAL_HEX;
214}
215
216#include "xlat/madvise_cmds.h"
217
218SYS_FUNC(madvise)
219{
220	printaddr(tcp->u_arg[0]);
221	tprintf(", %lu, ", tcp->u_arg[1]);
222	printxval(madvise_cmds, tcp->u_arg[2], "MADV_???");
223
224	return RVAL_DECODED;
225}
226
227#include "xlat/mlockall_flags.h"
228
229SYS_FUNC(mlockall)
230{
231	printflags(mlockall_flags, tcp->u_arg[0], "MCL_???");
232
233	return RVAL_DECODED;
234}
235
236#include "xlat/mctl_sync.h"
237
238SYS_FUNC(msync)
239{
240	/* addr */
241	printaddr(tcp->u_arg[0]);
242	/* len */
243	tprintf(", %lu, ", tcp->u_arg[1]);
244	/* flags */
245	printflags(mctl_sync, tcp->u_arg[2], "MS_???");
246
247	return RVAL_DECODED;
248}
249
250#include "xlat/mlock_flags.h"
251
252SYS_FUNC(mlock2)
253{
254	printaddr(tcp->u_arg[0]);
255	tprintf(", %lu, ", tcp->u_arg[1]);
256	printflags(mlock_flags, tcp->u_arg[2], "MLOCK_???");
257
258	return RVAL_DECODED;
259}
260
261SYS_FUNC(mincore)
262{
263	if (entering(tcp)) {
264		printaddr(tcp->u_arg[0]);
265		tprintf(", %lu, ", tcp->u_arg[1]);
266	} else {
267		unsigned long i, len;
268		char *vec = NULL;
269
270		len = tcp->u_arg[1];
271		if (syserror(tcp) || !verbose(tcp) ||
272		    !tcp->u_arg[2] || !(vec = malloc(len)) ||
273		    umoven(tcp, tcp->u_arg[2], len, vec) < 0)
274			printaddr(tcp->u_arg[2]);
275		else {
276			tprints("[");
277			for (i = 0; i < len; i++) {
278				if (abbrev(tcp) && i >= max_strlen) {
279					tprints("...");
280					break;
281				}
282				tprints((vec[i] & 1) ? "1" : "0");
283			}
284			tprints("]");
285		}
286		free(vec);
287	}
288	return 0;
289}
290
291#if defined ALPHA || defined IA64 || defined M68K \
292 || defined SPARC || defined SPARC64
293SYS_FUNC(getpagesize)
294{
295	if (exiting(tcp))
296		return RVAL_HEX;
297	return 0;
298}
299#endif
300
301SYS_FUNC(remap_file_pages)
302{
303	printaddr(tcp->u_arg[0]);
304	tprintf(", %lu, ", tcp->u_arg[1]);
305	printflags(mmap_prot, tcp->u_arg[2], "PROT_???");
306	tprintf(", %lu, ", tcp->u_arg[3]);
307#ifdef MAP_TYPE
308	printxval(mmap_flags, tcp->u_arg[4] & MAP_TYPE, "MAP_???");
309	addflags(mmap_flags, tcp->u_arg[4] & ~MAP_TYPE);
310#else
311	printflags(mmap_flags, tcp->u_arg[4], "MAP_???");
312#endif
313
314	return RVAL_DECODED;
315}
316
317#define MPOL_DEFAULT    0
318#define MPOL_PREFERRED  1
319#define MPOL_BIND       2
320#define MPOL_INTERLEAVE 3
321
322#define MPOL_F_NODE     (1<<0)
323#define MPOL_F_ADDR     (1<<1)
324
325#define MPOL_MF_STRICT  (1<<0)
326#define MPOL_MF_MOVE	(1<<1)
327#define MPOL_MF_MOVE_ALL (1<<2)
328
329#include "xlat/policies.h"
330#include "xlat/mbindflags.h"
331#include "xlat/mempolicyflags.h"
332#include "xlat/move_pages_flags.h"
333
334static void
335get_nodes(struct tcb *tcp, unsigned long ptr, unsigned long maxnodes, int err)
336{
337	unsigned long nlongs, size, end;
338
339	nlongs = (maxnodes + 8 * sizeof(long) - 1) / (8 * sizeof(long));
340	size = nlongs * sizeof(long);
341	end = ptr + size;
342	if (nlongs == 0 || ((err || verbose(tcp)) && (size * 8 == maxnodes)
343			    && (end > ptr))) {
344		unsigned long n, cur, abbrev_end;
345		int failed = 0;
346
347		if (abbrev(tcp)) {
348			abbrev_end = ptr + max_strlen * sizeof(long);
349			if (abbrev_end < ptr)
350				abbrev_end = end;
351		} else {
352			abbrev_end = end;
353		}
354		tprints(", {");
355		for (cur = ptr; cur < end; cur += sizeof(long)) {
356			if (cur > ptr)
357				tprints(", ");
358			if (cur >= abbrev_end) {
359				tprints("...");
360				break;
361			}
362			if (umoven(tcp, cur, sizeof(n), &n) < 0) {
363				tprints("?");
364				failed = 1;
365				break;
366			}
367			tprintf("%#0*lx", (int) sizeof(long) * 2 + 2, n);
368		}
369		tprints("}");
370		if (failed) {
371			tprints(" ");
372			printaddr(ptr);
373		}
374	} else {
375		tprints(" ");
376		printaddr(ptr);
377	}
378	tprintf(", %lu", maxnodes);
379}
380
381SYS_FUNC(mbind)
382{
383	printaddr(tcp->u_arg[0]);
384	tprintf(", %lu, ", tcp->u_arg[1]);
385	printxval(policies, tcp->u_arg[2], "MPOL_???");
386	get_nodes(tcp, tcp->u_arg[3], tcp->u_arg[4], 0);
387	tprints(", ");
388	printflags(mbindflags, tcp->u_arg[5], "MPOL_???");
389
390	return RVAL_DECODED;
391}
392
393SYS_FUNC(set_mempolicy)
394{
395	printxval(policies, tcp->u_arg[0], "MPOL_???");
396	get_nodes(tcp, tcp->u_arg[1], tcp->u_arg[2], 0);
397
398	return RVAL_DECODED;
399}
400
401SYS_FUNC(get_mempolicy)
402{
403	if (exiting(tcp)) {
404		int pol;
405		if (!umove_or_printaddr(tcp, tcp->u_arg[0], &pol))
406			printxval(policies, pol, "MPOL_???");
407		get_nodes(tcp, tcp->u_arg[1], tcp->u_arg[2], syserror(tcp));
408		tprints(", ");
409		printaddr(tcp->u_arg[3]);
410		tprints(", ");
411		printflags(mempolicyflags, tcp->u_arg[4], "MPOL_???");
412	}
413	return 0;
414}
415
416SYS_FUNC(migrate_pages)
417{
418	tprintf("%ld, ", (long) (pid_t) tcp->u_arg[0]);
419	get_nodes(tcp, tcp->u_arg[2], tcp->u_arg[1], 0);
420	tprints(", ");
421	get_nodes(tcp, tcp->u_arg[3], tcp->u_arg[1], 0);
422
423	return RVAL_DECODED;
424}
425
426SYS_FUNC(move_pages)
427{
428	if (entering(tcp)) {
429		unsigned long npages = tcp->u_arg[1];
430		tprintf("%ld, %lu, ", tcp->u_arg[0], npages);
431		if (tcp->u_arg[2] == 0)
432			tprints("NULL, ");
433		else {
434			unsigned int i;
435			long puser = tcp->u_arg[2];
436			tprints("{");
437			for (i = 0; i < npages; ++i) {
438				void *p;
439				if (i > 0)
440					tprints(", ");
441				if (umove(tcp, puser, &p) < 0) {
442					tprints("???");
443					break;
444				}
445				tprintf("%p", p);
446				puser += sizeof(void *);
447			}
448			tprints("}, ");
449		}
450		if (tcp->u_arg[3] == 0)
451			tprints("NULL, ");
452		else {
453			unsigned int i;
454			long nodeuser = tcp->u_arg[3];
455			tprints("{");
456			for (i = 0; i < npages; ++i) {
457				int node;
458				if (i > 0)
459					tprints(", ");
460				if (umove(tcp, nodeuser, &node) < 0) {
461					tprints("???");
462					break;
463				}
464				tprintf("%#x", node);
465				nodeuser += sizeof(int);
466			}
467			tprints("}, ");
468		}
469	} else {
470		unsigned long npages = tcp->u_arg[1];
471		if (tcp->u_arg[4] == 0)
472			tprints("NULL, ");
473		else {
474			unsigned int i;
475			long statususer = tcp->u_arg[4];
476			tprints("{");
477			for (i = 0; i < npages; ++i) {
478				int status;
479				if (i > 0)
480					tprints(", ");
481				if (umove(tcp, statususer, &status) < 0) {
482					tprints("???");
483					break;
484				}
485				tprintf("%#x", status);
486				statususer += sizeof(int);
487			}
488			tprints("}, ");
489		}
490		printflags(move_pages_flags, tcp->u_arg[5], "MPOL_???");
491	}
492	return 0;
493}
494
495#if defined(POWERPC)
496SYS_FUNC(subpage_prot)
497{
498	unsigned long cur, end, abbrev_end, entries;
499	unsigned int entry;
500
501	printaddr(tcp->u_arg[0]);
502	tprints(", ");
503	printaddr(tcp->u_arg[1]);
504	tprints(", ");
505	entries = tcp->u_arg[1] >> 16;
506	if (!entries || !tcp->u_arg[2]) {
507		tprints("{}");
508		return 0;
509	}
510	cur = tcp->u_arg[2];
511	end = cur + (sizeof(int) * entries);
512	if (!verbose(tcp) || end < (unsigned long) tcp->u_arg[2]) {
513		printaddr(tcp->u_arg[2]);
514		return 0;
515	}
516	if (abbrev(tcp)) {
517		abbrev_end = cur + (sizeof(int) * max_strlen);
518		if (abbrev_end > end)
519			abbrev_end = end;
520	}
521	else
522		abbrev_end = end;
523	tprints("{");
524	for (; cur < end; cur += sizeof(int)) {
525		if (cur > (unsigned long) tcp->u_arg[2])
526			tprints(", ");
527		if (cur >= abbrev_end) {
528			tprints("...");
529			break;
530		}
531		if (umove(tcp, cur, &entry) < 0) {
532			tprintf("??? [%#lx]", cur);
533			break;
534		}
535		else
536			tprintf("%#08x", entry);
537	}
538	tprints("}");
539
540	return RVAL_DECODED;
541}
542#endif
543