1/*
2 * Copyright (c) 2004 Ulrich Drepper <drepper@redhat.com>
3 * Copyright (c) 2005 Roland McGrath <roland@redhat.com>
4 * Copyright (c) 2012-2015 Dmitry V. Levin <ldv@altlinux.org>
5 * Copyright (c) 2014-2017 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 "defs.h"
32
33#include <sched.h>
34#include "sched_attr.h"
35
36#include "xlat/schedulers.h"
37#include "xlat/sched_flags.h"
38
39SYS_FUNC(sched_getscheduler)
40{
41	if (entering(tcp)) {
42		tprintf("%d", (int) tcp->u_arg[0]);
43	} else if (!syserror(tcp)) {
44		tcp->auxstr = xlookup(schedulers, (kernel_ulong_t) tcp->u_rval);
45		if (tcp->auxstr != NULL)
46			return RVAL_STR;
47	}
48	return 0;
49}
50
51SYS_FUNC(sched_setscheduler)
52{
53	tprintf("%d, ", (int) tcp->u_arg[0]);
54	printxval(schedulers, tcp->u_arg[1], "SCHED_???");
55	tprints(", ");
56	printnum_int(tcp, tcp->u_arg[2], "%d");
57
58	return RVAL_DECODED;
59}
60
61SYS_FUNC(sched_getparam)
62{
63	if (entering(tcp))
64		tprintf("%d, ", (int) tcp->u_arg[0]);
65	else
66		printnum_int(tcp, tcp->u_arg[1], "%d");
67	return 0;
68}
69
70SYS_FUNC(sched_setparam)
71{
72	tprintf("%d, ", (int) tcp->u_arg[0]);
73	printnum_int(tcp, tcp->u_arg[1], "%d");
74
75	return RVAL_DECODED;
76}
77
78SYS_FUNC(sched_get_priority_min)
79{
80	printxval(schedulers, tcp->u_arg[0], "SCHED_???");
81
82	return RVAL_DECODED;
83}
84
85SYS_FUNC(sched_rr_get_interval)
86{
87	if (entering(tcp)) {
88		tprintf("%d, ", (int) tcp->u_arg[0]);
89	} else {
90		if (syserror(tcp))
91			printaddr(tcp->u_arg[1]);
92		else
93			print_timespec(tcp, tcp->u_arg[1]);
94	}
95	return 0;
96}
97
98static void
99print_sched_attr(struct tcb *const tcp, const kernel_ulong_t addr,
100		 unsigned int usize)
101{
102	struct sched_attr attr = {};
103	unsigned int size;
104
105	if (usize) {
106		/* called from sched_getattr */
107		size = usize <= sizeof(attr) ? usize : (unsigned) sizeof(attr);
108		if (umoven_or_printaddr(tcp, addr, size, &attr))
109			return;
110		/* the number of bytes written by the kernel */
111		size = attr.size;
112	} else {
113		/* called from sched_setattr */
114		if (umove_or_printaddr(tcp, addr, &attr.size))
115			return;
116		usize = attr.size;
117		if (!usize)
118			usize = SCHED_ATTR_MIN_SIZE;
119		size = usize <= sizeof(attr) ? usize : (unsigned) sizeof(attr);
120		if (size >= SCHED_ATTR_MIN_SIZE) {
121			if (umoven_or_printaddr(tcp, addr, size, &attr))
122				return;
123		}
124	}
125
126	tprintf("{size=%u", attr.size);
127
128	if (size >= SCHED_ATTR_MIN_SIZE) {
129		tprints(", sched_policy=");
130		printxval(schedulers, attr.sched_policy, "SCHED_???");
131		tprints(", sched_flags=");
132		printflags64(sched_flags, attr.sched_flags, "SCHED_FLAG_???");
133
134#define PRINT_SCHED_FIELD(field, fmt)			\
135		tprintf(", " #field "=%" fmt, attr.field)
136
137		PRINT_SCHED_FIELD(sched_nice, "d");
138		PRINT_SCHED_FIELD(sched_priority, "u");
139		PRINT_SCHED_FIELD(sched_runtime, PRIu64);
140		PRINT_SCHED_FIELD(sched_deadline, PRIu64);
141		PRINT_SCHED_FIELD(sched_period, PRIu64);
142
143		if (usize > size)
144			tprints(", ...");
145	}
146
147	tprints("}");
148}
149
150SYS_FUNC(sched_setattr)
151{
152	if (entering(tcp)) {
153		tprintf("%d, ", (int) tcp->u_arg[0]);
154		print_sched_attr(tcp, tcp->u_arg[1], 0);
155	} else {
156		struct sched_attr attr;
157
158		if (verbose(tcp) && tcp->u_error == E2BIG
159		    && umove(tcp, tcp->u_arg[1], &attr.size) == 0) {
160			tprintf(" => {size=%u}", attr.size);
161		}
162
163		tprintf(", %u", (unsigned int) tcp->u_arg[2]);
164	}
165
166	return 0;
167}
168
169SYS_FUNC(sched_getattr)
170{
171	if (entering(tcp)) {
172		tprintf("%d, ", (int) tcp->u_arg[0]);
173	} else {
174		const unsigned int size = tcp->u_arg[2];
175
176		if (size)
177			print_sched_attr(tcp, tcp->u_arg[1], size);
178		else
179			printaddr(tcp->u_arg[1]);
180		tprints(", ");
181#ifdef AARCH64
182		/*
183		 * Due to a subtle gcc bug that leads to miscompiled aarch64
184		 * kernels, the 3rd argument of sched_getattr is not quite 32-bit
185		 * as on other architectures.  For more details see
186		 * https://sourceforge.net/p/strace/mailman/message/35721703/
187		 */
188		if (syserror(tcp))
189			print_abnormal_hi(tcp->u_arg[2]);
190#endif
191		tprintf("%u", size);
192		tprintf(", %u", (unsigned int) tcp->u_arg[3]);
193	}
194
195	return 0;
196}
197