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