mem.c revision 15fc6a2add5cc636435b120075d2c27637528b11
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#if defined(I386)
37# include <asm/ldt.h>
38# ifdef HAVE_STRUCT_USER_DESC
39#  define modify_ldt_ldt_s user_desc
40# endif
41#endif
42
43static unsigned long
44get_pagesize()
45{
46	static unsigned long pagesize;
47
48	if (!pagesize)
49		pagesize = sysconf(_SC_PAGESIZE);
50	return pagesize;
51}
52
53int
54sys_brk(struct tcb *tcp)
55{
56	if (entering(tcp)) {
57		tprintf("%#lx", tcp->u_arg[0]);
58	}
59	return RVAL_HEX;
60}
61
62static const struct xlat mmap_prot[] = {
63	{ PROT_NONE,	"PROT_NONE",	},
64	{ PROT_READ,	"PROT_READ"	},
65	{ PROT_WRITE,	"PROT_WRITE"	},
66	{ PROT_EXEC,	"PROT_EXEC"	},
67#ifdef PROT_SEM
68	{ PROT_SEM,	"PROT_SEM"	},
69#endif
70#ifdef PROT_GROWSDOWN
71	{ PROT_GROWSDOWN,"PROT_GROWSDOWN"},
72#endif
73#ifdef PROT_GROWSUP
74	{ PROT_GROWSUP, "PROT_GROWSUP"	},
75#endif
76#ifdef PROT_SAO
77	{ PROT_SAO,	"PROT_SAO"	},
78#endif
79	{ 0,		NULL		},
80};
81
82static const struct xlat mmap_flags[] = {
83	{ MAP_SHARED,	"MAP_SHARED"	},
84	{ MAP_PRIVATE,	"MAP_PRIVATE"	},
85	{ MAP_FIXED,	"MAP_FIXED"	},
86#ifdef MAP_ANONYMOUS
87	{ MAP_ANONYMOUS,"MAP_ANONYMOUS"	},
88#endif
89#ifdef MAP_32BIT
90	{ MAP_32BIT,	"MAP_32BIT"	},
91#endif
92#ifdef MAP_RENAME
93	{ MAP_RENAME,	"MAP_RENAME"	},
94#endif
95#ifdef MAP_NORESERVE
96	{ MAP_NORESERVE,"MAP_NORESERVE"	},
97#endif
98#ifdef MAP_POPULATE
99	{ MAP_POPULATE, "MAP_POPULATE" },
100#endif
101#ifdef MAP_NONBLOCK
102	{ MAP_NONBLOCK, "MAP_NONBLOCK" },
103#endif
104	/*
105	 * XXX - this was introduced in SunOS 4.x to distinguish between
106	 * the old pre-4.x "mmap()", which:
107	 *
108	 *	only let you map devices with an "mmap" routine (e.g.,
109	 *	frame buffers) in;
110	 *
111	 *	required you to specify the mapping address;
112	 *
113	 *	returned 0 on success and -1 on failure;
114	 *
115	 * memory and which, and the 4.x "mmap()" which:
116	 *
117	 *	can map plain files;
118	 *
119	 *	can be asked to pick where to map the file;
120	 *
121	 *	returns the address where it mapped the file on success
122	 *	and -1 on failure.
123	 *
124	 * It's not actually used in source code that calls "mmap()"; the
125	 * "mmap()" routine adds it for you.
126	 *
127	 * It'd be nice to come up with some way of eliminating it from
128	 * the flags, e.g. reporting calls *without* it as "old_mmap()"
129	 * and calls with it as "mmap()".
130	 */
131#ifdef _MAP_NEW
132	{ _MAP_NEW,	"_MAP_NEW"	},
133#endif
134#ifdef MAP_GROWSDOWN
135	{ MAP_GROWSDOWN,"MAP_GROWSDOWN"	},
136#endif
137#ifdef MAP_DENYWRITE
138	{ MAP_DENYWRITE,"MAP_DENYWRITE"	},
139#endif
140#ifdef MAP_EXECUTABLE
141	{ MAP_EXECUTABLE,"MAP_EXECUTABLE"},
142#endif
143#ifdef MAP_INHERIT
144	{ MAP_INHERIT,	"MAP_INHERIT"	},
145#endif
146#ifdef MAP_FILE
147	{ MAP_FILE,	"MAP_FILE"	},
148#endif
149#ifdef MAP_LOCKED
150	{ MAP_LOCKED,	"MAP_LOCKED"	},
151#endif
152	/* FreeBSD ones */
153#if defined(MAP_ANON) && (!defined(MAP_ANONYMOUS) || MAP_ANON != MAP_ANONYMOUS)
154	{ MAP_ANON,	"MAP_ANON"	},
155#endif
156#ifdef MAP_HASSEMAPHORE
157	{ MAP_HASSEMAPHORE,"MAP_HASSEMAPHORE"},
158#endif
159#ifdef MAP_STACK
160	{ MAP_STACK,	"MAP_STACK"	},
161#endif
162#if defined MAP_UNINITIALIZED && MAP_UNINITIALIZED > 0
163	{ MAP_UNINITIALIZED,"MAP_UNINITIALIZED"},
164#endif
165#ifdef MAP_NOSYNC
166	{ MAP_NOSYNC,	"MAP_NOSYNC"	},
167#endif
168#ifdef MAP_NOCORE
169	{ MAP_NOCORE,	"MAP_NOCORE"	},
170#endif
171	{ 0,		NULL		},
172};
173
174static int
175print_mmap(struct tcb *tcp, long *u_arg, unsigned long long offset)
176{
177	if (entering(tcp)) {
178		/* addr */
179		if (!u_arg[0])
180			tprints("NULL, ");
181		else
182			tprintf("%#lx, ", u_arg[0]);
183		/* len */
184		tprintf("%lu, ", u_arg[1]);
185		/* prot */
186		printflags(mmap_prot, u_arg[2], "PROT_???");
187		tprints(", ");
188		/* flags */
189#ifdef MAP_TYPE
190		printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
191		addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
192#else
193		printflags(mmap_flags, u_arg[3], "MAP_???");
194#endif
195		tprints(", ");
196		/* fd */
197		printfd(tcp, u_arg[4]);
198		/* offset */
199		tprintf(", %#llx", offset);
200	}
201	return RVAL_HEX;
202}
203
204/* Syscall name<->function correspondence is messed up on many arches.
205 * For example:
206 * i386 has __NR_mmap == 90, and it is "old mmap", and
207 * also it has __NR_mmap2 == 192, which is a "new mmap with page offsets".
208 * But x86_64 has just one __NR_mmap == 9, a "new mmap with byte offsets".
209 * Confused? Me too!
210 */
211
212/* Params are pointed to by u_arg[0], offset is in bytes */
213int
214sys_old_mmap(struct tcb *tcp)
215{
216	long u_arg[6];
217#if defined(IA64)
218	/*
219	 * IA64 processes never call this routine, they only use the
220	 * new 'sys_mmap' interface. Only IA32 processes come here.
221	 */
222	int i;
223	unsigned narrow_arg[6];
224	if (umoven(tcp, tcp->u_arg[0], sizeof(narrow_arg), (char *) narrow_arg) == -1)
225		return 0;
226	for (i = 0; i < 6; i++)
227		u_arg[i] = (unsigned long) narrow_arg[i];
228#elif defined(X86_64)
229	/* We are here only in personality 1 (i386) */
230	int i;
231	unsigned narrow_arg[6];
232	if (umoven(tcp, tcp->u_arg[0], sizeof(narrow_arg), (char *) narrow_arg) == -1)
233		return 0;
234	for (i = 0; i < 6; ++i)
235		u_arg[i] = (unsigned long) narrow_arg[i];
236#else
237	if (umoven(tcp, tcp->u_arg[0], sizeof(u_arg), (char *) u_arg) == -1)
238		return 0;
239#endif
240	return print_mmap(tcp, u_arg, (unsigned long) u_arg[5]);
241}
242
243#if defined(S390)
244/* Params are pointed to by u_arg[0], offset is in pages */
245int
246sys_old_mmap_pgoff(struct tcb *tcp)
247{
248	long u_arg[5];
249	int i;
250	unsigned narrow_arg[6];
251	unsigned long long offset;
252	if (umoven(tcp, tcp->u_arg[0], sizeof(narrow_arg), (char *) narrow_arg) == -1)
253		return 0;
254	for (i = 0; i < 5; i++)
255		u_arg[i] = (unsigned long) narrow_arg[i];
256	offset = narrow_arg[5];
257	offset *= get_pagesize();
258	return print_mmap(tcp, u_arg, offset);
259}
260#endif
261
262/* Params are passed directly, offset is in bytes */
263int
264sys_mmap(struct tcb *tcp)
265{
266	unsigned long long offset = (unsigned long) tcp->u_arg[5];
267#if defined(LINUX_MIPSN32) || defined(X32)
268	/* Try test/x32_mmap.c */
269	offset = tcp->ext_arg[5];
270#endif
271	/* Example of kernel-side handling of this variety of mmap:
272	 * arch/x86/kernel/sys_x86_64.c::SYSCALL_DEFINE6(mmap, ...) calls
273	 * sys_mmap_pgoff(..., off >> PAGE_SHIFT); i.e. off is in bytes,
274	 * since the above code converts off to pages.
275	 */
276	return print_mmap(tcp, tcp->u_arg, offset);
277}
278
279/* Params are passed directly, offset is in pages */
280int
281sys_mmap_pgoff(struct tcb *tcp)
282{
283	/* Try test/mmap_offset_decode.c */
284	unsigned long long offset;
285	offset = (unsigned long) tcp->u_arg[5];
286	offset *= get_pagesize();
287	return print_mmap(tcp, tcp->u_arg, offset);
288}
289
290/* Params are passed directly, offset is in 4k units */
291int
292sys_mmap_4koff(struct tcb *tcp)
293{
294	unsigned long long offset;
295	offset = (unsigned long) tcp->u_arg[5];
296	offset <<= 12;
297	return print_mmap(tcp, tcp->u_arg, offset);
298}
299
300int
301sys_munmap(struct tcb *tcp)
302{
303	if (entering(tcp)) {
304		tprintf("%#lx, %lu",
305			tcp->u_arg[0], tcp->u_arg[1]);
306	}
307	return 0;
308}
309
310int
311sys_mprotect(struct tcb *tcp)
312{
313	if (entering(tcp)) {
314		tprintf("%#lx, %lu, ",
315			tcp->u_arg[0], tcp->u_arg[1]);
316		printflags(mmap_prot, tcp->u_arg[2], "PROT_???");
317	}
318	return 0;
319}
320
321static const struct xlat mremap_flags[] = {
322	{ MREMAP_MAYMOVE,	"MREMAP_MAYMOVE"	},
323#ifdef MREMAP_FIXED
324	{ MREMAP_FIXED,		"MREMAP_FIXED"		},
325#endif
326	{ 0,			NULL			}
327};
328
329int
330sys_mremap(struct tcb *tcp)
331{
332	if (entering(tcp)) {
333		tprintf("%#lx, %lu, %lu, ", tcp->u_arg[0], tcp->u_arg[1],
334			tcp->u_arg[2]);
335		printflags(mremap_flags, tcp->u_arg[3], "MREMAP_???");
336#ifdef MREMAP_FIXED
337		if ((tcp->u_arg[3] & (MREMAP_MAYMOVE | MREMAP_FIXED)) ==
338		    (MREMAP_MAYMOVE | MREMAP_FIXED))
339			tprintf(", %#lx", tcp->u_arg[4]);
340#endif
341	}
342	return RVAL_HEX;
343}
344
345static const struct xlat madvise_cmds[] = {
346#ifdef MADV_NORMAL
347	{ MADV_NORMAL,		"MADV_NORMAL" },
348#endif
349#ifdef MADV_RANDOM
350	{ MADV_RANDOM,		"MADV_RANDOM" },
351#endif
352#ifdef MADV_SEQUENTIAL
353	{ MADV_SEQUENTIAL,	"MADV_SEQUENTIAL" },
354#endif
355#ifdef MADV_WILLNEED
356	{ MADV_WILLNEED,	"MADV_WILLNEED" },
357#endif
358#ifdef MADV_DONTNEED
359	{ MADV_DONTNEED,	"MADV_DONTNEED" },
360#endif
361#ifdef MADV_REMOVE
362	{ MADV_REMOVE,		"MADV_REMOVE" },
363#endif
364#ifdef MADV_DONTFORK
365	{ MADV_DONTFORK,	"MADV_DONTFORK" },
366#endif
367#ifdef MADV_DOFORK
368	{ MADV_DOFORK,		"MADV_DOFORK" },
369#endif
370#ifdef MADV_HWPOISON
371	{ MADV_HWPOISON,	"MADV_HWPOISON" },
372#endif
373#ifdef MADV_SOFT_OFFLINE
374	{ MADV_SOFT_OFFLINE,	"MADV_SOFT_OFFLINE" },
375#endif
376#ifdef MADV_MERGEABLE
377	{ MADV_MERGEABLE,	"MADV_MERGEABLE" },
378#endif
379#ifdef MADV_UNMERGEABLE
380	{ MADV_UNMERGEABLE,	"MADV_UNMERGEABLE" },
381#endif
382#ifdef MADV_HUGEPAGE
383	{ MADV_HUGEPAGE,	"MADV_HUGEPAGE" },
384#endif
385#ifdef MADV_NOHUGEPAGE
386	{ MADV_NOHUGEPAGE,	"MADV_NOHUGEPAGE" },
387#endif
388#ifdef MADV_DONTDUMP
389	{ MADV_DONTDUMP,	"MADV_DONTDUMP" },
390#endif
391#ifdef MADV_DODUMP
392	{ MADV_DODUMP,		"MADV_DODUMP" },
393#endif
394	{ 0,			NULL },
395};
396
397int
398sys_madvise(struct tcb *tcp)
399{
400	if (entering(tcp)) {
401		tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
402		printxval(madvise_cmds, tcp->u_arg[2], "MADV_???");
403	}
404	return 0;
405}
406
407static const struct xlat mlockall_flags[] = {
408#ifdef MCL_CURRENT
409	{ MCL_CURRENT,	"MCL_CURRENT" },
410#endif
411#ifdef MCL_FUTURE
412	{ MCL_FUTURE,	"MCL_FUTURE" },
413#endif
414	{ 0,		NULL}
415};
416
417int
418sys_mlockall(struct tcb *tcp)
419{
420	if (entering(tcp)) {
421		printflags(mlockall_flags, tcp->u_arg[0], "MCL_???");
422	}
423	return 0;
424}
425
426#ifdef MS_ASYNC
427
428static const struct xlat mctl_sync[] = {
429#ifdef MS_SYNC
430	{ MS_SYNC,	"MS_SYNC"	},
431#endif
432	{ MS_ASYNC,	"MS_ASYNC"	},
433	{ MS_INVALIDATE,"MS_INVALIDATE"	},
434	{ 0,		NULL		},
435};
436
437int
438sys_msync(struct tcb *tcp)
439{
440	if (entering(tcp)) {
441		/* addr */
442		tprintf("%#lx", tcp->u_arg[0]);
443		/* len */
444		tprintf(", %lu, ", tcp->u_arg[1]);
445		/* flags */
446		printflags(mctl_sync, tcp->u_arg[2], "MS_???");
447	}
448	return 0;
449}
450
451#endif /* MS_ASYNC */
452
453#ifdef MC_SYNC
454
455static const struct xlat mctl_funcs[] = {
456	{ MC_LOCK,	"MC_LOCK"	},
457	{ MC_LOCKAS,	"MC_LOCKAS"	},
458	{ MC_SYNC,	"MC_SYNC"	},
459	{ MC_UNLOCK,	"MC_UNLOCK"	},
460	{ MC_UNLOCKAS,	"MC_UNLOCKAS"	},
461	{ 0,		NULL		},
462};
463
464static const struct xlat mctl_lockas[] = {
465	{ MCL_CURRENT,	"MCL_CURRENT"	},
466	{ MCL_FUTURE,	"MCL_FUTURE"	},
467	{ 0,		NULL		},
468};
469
470int
471sys_mctl(struct tcb *tcp)
472{
473	int arg, function;
474
475	if (entering(tcp)) {
476		/* addr */
477		tprintf("%#lx", tcp->u_arg[0]);
478		/* len */
479		tprintf(", %lu, ", tcp->u_arg[1]);
480		/* function */
481		function = tcp->u_arg[2];
482		printflags(mctl_funcs, function, "MC_???");
483		/* arg */
484		arg = tcp->u_arg[3];
485		tprints(", ");
486		switch (function) {
487		case MC_SYNC:
488			printflags(mctl_sync, arg, "MS_???");
489			break;
490		case MC_LOCKAS:
491			printflags(mctl_lockas, arg, "MCL_???");
492			break;
493		default:
494			tprintf("%#x", arg);
495			break;
496		}
497	}
498	return 0;
499}
500
501#endif /* MC_SYNC */
502
503int
504sys_mincore(struct tcb *tcp)
505{
506	if (entering(tcp)) {
507		tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
508	} else {
509		unsigned long i, len;
510		char *vec = NULL;
511
512		len = tcp->u_arg[1];
513		if (syserror(tcp) || tcp->u_arg[2] == 0 ||
514			(vec = malloc(len)) == NULL ||
515			umoven(tcp, tcp->u_arg[2], len, vec) < 0)
516			tprintf("%#lx", tcp->u_arg[2]);
517		else {
518			tprints("[");
519			for (i = 0; i < len; i++) {
520				if (abbrev(tcp) && i >= max_strlen) {
521					tprints("...");
522					break;
523				}
524				tprints((vec[i] & 1) ? "1" : "0");
525			}
526			tprints("]");
527		}
528		free(vec);
529	}
530	return 0;
531}
532
533#if defined(ALPHA) || defined(IA64) || defined(SPARC) || defined(SPARC64)
534int
535sys_getpagesize(struct tcb *tcp)
536{
537	if (exiting(tcp))
538		return RVAL_HEX;
539	return 0;
540}
541#endif
542
543#if defined(I386)
544void
545print_ldt_entry(struct modify_ldt_ldt_s *ldt_entry)
546{
547	tprintf("base_addr:%#08lx, "
548		"limit:%d, "
549		"seg_32bit:%d, "
550		"contents:%d, "
551		"read_exec_only:%d, "
552		"limit_in_pages:%d, "
553		"seg_not_present:%d, "
554		"useable:%d}",
555		(long) ldt_entry->base_addr,
556		ldt_entry->limit,
557		ldt_entry->seg_32bit,
558		ldt_entry->contents,
559		ldt_entry->read_exec_only,
560		ldt_entry->limit_in_pages,
561		ldt_entry->seg_not_present,
562		ldt_entry->useable);
563}
564
565int
566sys_modify_ldt(struct tcb *tcp)
567{
568	if (entering(tcp)) {
569		struct modify_ldt_ldt_s copy;
570		tprintf("%ld", tcp->u_arg[0]);
571		if (tcp->u_arg[1] == 0
572				|| tcp->u_arg[2] != sizeof(struct modify_ldt_ldt_s)
573				|| umove(tcp, tcp->u_arg[1], &copy) == -1)
574			tprintf(", %lx", tcp->u_arg[1]);
575		else {
576			tprintf(", {entry_number:%d, ", copy.entry_number);
577			if (!verbose(tcp))
578				tprints("...}");
579			else {
580				print_ldt_entry(&copy);
581			}
582		}
583		tprintf(", %lu", tcp->u_arg[2]);
584	}
585	return 0;
586}
587
588int
589sys_set_thread_area(struct tcb *tcp)
590{
591	struct modify_ldt_ldt_s copy;
592	if (entering(tcp)) {
593		if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
594			if (copy.entry_number == -1)
595				tprintf("{entry_number:%d -> ",
596					copy.entry_number);
597			else
598				tprints("{entry_number:");
599		}
600	} else {
601		if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
602			tprintf("%d, ", copy.entry_number);
603			if (!verbose(tcp))
604				tprints("...}");
605			else {
606				print_ldt_entry(&copy);
607			}
608		} else {
609			tprintf("%lx", tcp->u_arg[0]);
610		}
611	}
612	return 0;
613
614}
615
616int
617sys_get_thread_area(struct tcb *tcp)
618{
619	struct modify_ldt_ldt_s copy;
620	if (exiting(tcp)) {
621		if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
622			tprintf("{entry_number:%d, ", copy.entry_number);
623			if (!verbose(tcp))
624				tprints("...}");
625			else {
626				print_ldt_entry(&copy);
627			}
628		} else {
629			tprintf("%lx", tcp->u_arg[0]);
630		}
631	}
632	return 0;
633
634}
635#endif /* I386 */
636
637#if defined(M68K)
638int
639sys_set_thread_area(struct tcb *tcp)
640{
641	if (entering(tcp))
642		tprintf("%#lx", tcp->u_arg[0]);
643	return 0;
644
645}
646
647int
648sys_get_thread_area(struct tcb *tcp)
649{
650	return RVAL_HEX;
651}
652#endif
653
654int
655sys_remap_file_pages(struct tcb *tcp)
656{
657	if (entering(tcp)) {
658		tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
659		printflags(mmap_prot, tcp->u_arg[2], "PROT_???");
660		tprintf(", %lu, ", tcp->u_arg[3]);
661#ifdef MAP_TYPE
662		printxval(mmap_flags, tcp->u_arg[4] & MAP_TYPE, "MAP_???");
663		addflags(mmap_flags, tcp->u_arg[4] & ~MAP_TYPE);
664#else
665		printflags(mmap_flags, tcp->u_arg[4], "MAP_???");
666#endif
667	}
668	return 0;
669}
670
671#define MPOL_DEFAULT    0
672#define MPOL_PREFERRED  1
673#define MPOL_BIND       2
674#define MPOL_INTERLEAVE 3
675
676#define MPOL_F_NODE     (1<<0)
677#define MPOL_F_ADDR     (1<<1)
678
679#define MPOL_MF_STRICT  (1<<0)
680#define MPOL_MF_MOVE	(1<<1)
681#define MPOL_MF_MOVE_ALL (1<<2)
682
683static const struct xlat policies[] = {
684	{ MPOL_DEFAULT,		"MPOL_DEFAULT"		},
685	{ MPOL_PREFERRED,	"MPOL_PREFERRED"	},
686	{ MPOL_BIND,		"MPOL_BIND"		},
687	{ MPOL_INTERLEAVE,	"MPOL_INTERLEAVE"	},
688	{ 0,			NULL			}
689};
690
691static const struct xlat mbindflags[] = {
692	{ MPOL_MF_STRICT,	"MPOL_MF_STRICT"	},
693	{ MPOL_MF_MOVE,		"MPOL_MF_MOVE"		},
694	{ MPOL_MF_MOVE_ALL,	"MPOL_MF_MOVE_ALL"	},
695	{ 0,			NULL			}
696};
697
698static const struct xlat mempolicyflags[] = {
699	{ MPOL_F_NODE,		"MPOL_F_NODE"		},
700	{ MPOL_F_ADDR,		"MPOL_F_ADDR"		},
701	{ 0,			NULL			}
702};
703
704static const struct xlat move_pages_flags[] = {
705	{ MPOL_MF_MOVE,		"MPOL_MF_MOVE"		},
706	{ MPOL_MF_MOVE_ALL,	"MPOL_MF_MOVE_ALL"	},
707	{ 0,			NULL			}
708};
709
710static void
711get_nodes(struct tcb *tcp, unsigned long ptr, unsigned long maxnodes, int err)
712{
713	unsigned long nlongs, size, end;
714
715	nlongs = (maxnodes + 8 * sizeof(long) - 1) / (8 * sizeof(long));
716	size = nlongs * sizeof(long);
717	end = ptr + size;
718	if (nlongs == 0 || ((err || verbose(tcp)) && (size * 8 == maxnodes)
719			    && (end > ptr))) {
720		unsigned long n, cur, abbrev_end;
721		int failed = 0;
722
723		if (abbrev(tcp)) {
724			abbrev_end = ptr + max_strlen * sizeof(long);
725			if (abbrev_end < ptr)
726				abbrev_end = end;
727		} else {
728			abbrev_end = end;
729		}
730		tprints(", {");
731		for (cur = ptr; cur < end; cur += sizeof(long)) {
732			if (cur > ptr)
733				tprints(", ");
734			if (cur >= abbrev_end) {
735				tprints("...");
736				break;
737			}
738			if (umoven(tcp, cur, sizeof(n), (char *) &n) < 0) {
739				tprints("?");
740				failed = 1;
741				break;
742			}
743			tprintf("%#0*lx", (int) sizeof(long) * 2 + 2, n);
744		}
745		tprints("}");
746		if (failed)
747			tprintf(" %#lx", ptr);
748	} else
749		tprintf(", %#lx", ptr);
750	tprintf(", %lu", maxnodes);
751}
752
753int
754sys_mbind(struct tcb *tcp)
755{
756	if (entering(tcp)) {
757		tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
758		printxval(policies, tcp->u_arg[2], "MPOL_???");
759		get_nodes(tcp, tcp->u_arg[3], tcp->u_arg[4], 0);
760		tprints(", ");
761		printflags(mbindflags, tcp->u_arg[5], "MPOL_???");
762	}
763	return 0;
764}
765
766int
767sys_set_mempolicy(struct tcb *tcp)
768{
769	if (entering(tcp)) {
770		printxval(policies, tcp->u_arg[0], "MPOL_???");
771		get_nodes(tcp, tcp->u_arg[1], tcp->u_arg[2], 0);
772	}
773	return 0;
774}
775
776int
777sys_get_mempolicy(struct tcb *tcp)
778{
779	if (exiting(tcp)) {
780		int pol;
781		if (tcp->u_arg[0] == 0)
782			tprints("NULL");
783		else if (syserror(tcp) || umove(tcp, tcp->u_arg[0], &pol) < 0)
784			tprintf("%#lx", tcp->u_arg[0]);
785		else
786			printxval(policies, pol, "MPOL_???");
787		get_nodes(tcp, tcp->u_arg[1], tcp->u_arg[2], syserror(tcp));
788		tprintf(", %#lx, ", tcp->u_arg[3]);
789		printflags(mempolicyflags, tcp->u_arg[4], "MPOL_???");
790	}
791	return 0;
792}
793
794int
795sys_migrate_pages(struct tcb *tcp)
796{
797	if (entering(tcp)) {
798		tprintf("%ld, ", (long) (pid_t) tcp->u_arg[0]);
799		get_nodes(tcp, tcp->u_arg[2], tcp->u_arg[1], 0);
800		tprints(", ");
801		get_nodes(tcp, tcp->u_arg[3], tcp->u_arg[1], 0);
802	}
803	return 0;
804}
805
806int
807sys_move_pages(struct tcb *tcp)
808{
809	if (entering(tcp)) {
810		unsigned long npages = tcp->u_arg[1];
811		tprintf("%ld, %lu, ", tcp->u_arg[0], npages);
812		if (tcp->u_arg[2] == 0)
813			tprints("NULL, ");
814		else {
815			int i;
816			long puser = tcp->u_arg[2];
817			tprints("{");
818			for (i = 0; i < npages; ++i) {
819				void *p;
820				if (i > 0)
821					tprints(", ");
822				if (umove(tcp, puser, &p) < 0) {
823					tprints("???");
824					break;
825				}
826				tprintf("%p", p);
827				puser += sizeof(void *);
828			}
829			tprints("}, ");
830		}
831		if (tcp->u_arg[3] == 0)
832			tprints("NULL, ");
833		else {
834			int i;
835			long nodeuser = tcp->u_arg[3];
836			tprints("{");
837			for (i = 0; i < npages; ++i) {
838				int node;
839				if (i > 0)
840					tprints(", ");
841				if (umove(tcp, nodeuser, &node) < 0) {
842					tprints("???");
843					break;
844				}
845				tprintf("%#x", node);
846				nodeuser += sizeof(int);
847			}
848			tprints("}, ");
849		}
850	}
851	if (exiting(tcp)) {
852		unsigned long npages = tcp->u_arg[1];
853		if (tcp->u_arg[4] == 0)
854			tprints("NULL, ");
855		else {
856			int i;
857			long statususer = tcp->u_arg[4];
858			tprints("{");
859			for (i = 0; i < npages; ++i) {
860				int status;
861				if (i > 0)
862					tprints(", ");
863				if (umove(tcp, statususer, &status) < 0) {
864					tprints("???");
865					break;
866				}
867				tprintf("%#x", status);
868				statususer += sizeof(int);
869			}
870			tprints("}, ");
871		}
872		printflags(move_pages_flags, tcp->u_arg[5], "MPOL_???");
873	}
874	return 0;
875}
876
877#if defined(POWERPC)
878int
879sys_subpage_prot(struct tcb *tcp)
880{
881	if (entering(tcp)) {
882		unsigned long cur, end, abbrev_end, entries;
883		unsigned int entry;
884
885		tprintf("%#lx, %#lx, ", tcp->u_arg[0], tcp->u_arg[1]);
886		entries = tcp->u_arg[1] >> 16;
887		if (!entries || !tcp->u_arg[2]) {
888			tprints("{}");
889			return 0;
890		}
891		cur = tcp->u_arg[2];
892		end = cur + (sizeof(int) * entries);
893		if (!verbose(tcp) || end < tcp->u_arg[2]) {
894			tprintf("%#lx", tcp->u_arg[2]);
895			return 0;
896		}
897		if (abbrev(tcp)) {
898			abbrev_end = cur + (sizeof(int) * max_strlen);
899			if (abbrev_end > end)
900				abbrev_end = end;
901		}
902		else
903			abbrev_end = end;
904		tprints("{");
905		for (; cur < end; cur += sizeof(int)) {
906			if (cur > tcp->u_arg[2])
907				tprints(", ");
908			if (cur >= abbrev_end) {
909				tprints("...");
910				break;
911			}
912			if (umove(tcp, cur, &entry) < 0) {
913				tprintf("??? [%#lx]", cur);
914				break;
915			}
916			else
917				tprintf("%#08x", entry);
918		}
919		tprints("}");
920	}
921
922	return 0;
923}
924#endif
925