xref: /freebsd/usr.bin/kdump/linux.c (revision 1f1e2261)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/uio.h>
33 #include <sys/ktrace.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sysdecode.h>
40 
41 #include "kdump.h"
42 
43 #ifdef __amd64__
44 #include <amd64/linux/linux.h>
45 #include <amd64/linux32/linux32_syscall.h>
46 #elif __aarch64__
47 #include <arm64/linux/linux.h>
48 #elif __i386__
49 #include <i386/linux/linux.h>
50 #endif
51 
52 #include <compat/linux/linux.h>
53 #include <compat/linux/linux_file.h>
54 
55 static void
56 print_linux_signal(int signo)
57 {
58 	const char *signame;
59 
60 	signame = sysdecode_linux_signal(signo);
61 	if (signame != NULL)
62 		printf("%s", signame);
63 	else
64 		printf("SIG %d", signo);
65 }
66 
67 void
68 ktrsyscall_linux(struct ktr_syscall *ktr, register_t **resip,
69     int *resnarg, char *resc)
70 {
71 	int narg = ktr->ktr_narg;
72 	register_t *ip, *first;
73 	int quad_align, quad_slots;
74 	char c;
75 
76 	ip = first = &ktr->ktr_args[0];
77 	c = *resc;
78 	quad_align = 0;
79 	quad_slots = 1;
80 	switch (ktr->ktr_code) {
81 	case LINUX_SYS_linux_faccessat:
82 	case LINUX_SYS_linux_fchmodat:
83 	case LINUX_SYS_linux_fchownat:
84 #ifdef LINUX_SYS_linux_newfstatat
85 	case LINUX_SYS_linux_newfstatat:
86 #endif
87 #ifdef LINUX_SYS_linux_fstatat64
88 	case LINUX_SYS_linux_fstatat64:
89 #endif
90 #ifdef LINUX_SYS_linux_futimesat
91 	case LINUX_SYS_linux_futimesat:
92 #endif
93 	case LINUX_SYS_linux_linkat:
94 	case LINUX_SYS_linux_mkdirat:
95 	case LINUX_SYS_linux_mknodat:
96 	case LINUX_SYS_linux_openat:
97 	case LINUX_SYS_linux_readlinkat:
98 	case LINUX_SYS_linux_renameat:
99 	case LINUX_SYS_linux_unlinkat:
100 	case LINUX_SYS_linux_utimensat:
101 		putchar('(');
102 		print_integer_arg_valid(sysdecode_atfd, *ip);
103 		c = ',';
104 		ip++;
105 		narg--;
106 		break;
107 	}
108 	switch (ktr->ktr_code) {
109 #ifdef LINUX_SYS_linux_access
110 	case LINUX_SYS_linux_access:
111 #endif
112 	case LINUX_SYS_linux_faccessat:
113 		print_number(ip, narg, c);
114 		putchar(',');
115 		print_mask_arg(sysdecode_access_mode, *ip);
116 		ip++;
117 		narg--;
118 		break;
119 #ifdef LINUX_SYS_linux_chmod
120 	case LINUX_SYS_linux_chmod:
121 #endif
122 	case LINUX_SYS_linux_fchmodat:
123 		print_number(ip, narg, c);
124 		putchar(',');
125 		decode_filemode(*ip);
126 		ip++;
127 		narg--;
128 		break;
129 	case LINUX_SYS_linux_mknodat:
130 		print_number(ip, narg, c);
131 		putchar(',');
132 		decode_filemode(*ip);
133 		ip++;
134 		narg--;
135 		break;
136 #ifdef LINUX_SYS_linux_mkdir
137 	case LINUX_SYS_linux_mkdir:
138 #endif
139 	case LINUX_SYS_linux_mkdirat:
140 		print_number(ip, narg, c);
141 		putchar(',');
142 		decode_filemode(*ip);
143 		ip++;
144 		narg--;
145 		break;
146 	case LINUX_SYS_linux_linkat:
147 	case LINUX_SYS_linux_renameat:
148 	case LINUX_SYS_linux_symlinkat:
149 		print_number(ip, narg, c);
150 		putchar(',');
151 		print_integer_arg_valid(sysdecode_atfd, *ip);
152 		ip++;
153 		narg--;
154 		print_number(ip, narg, c);
155 		break;
156 	case LINUX_SYS_linux_fchownat:
157 		print_number(ip, narg, c);
158 		print_number(ip, narg, c);
159 		print_number(ip, narg, c);
160 		break;
161 #ifdef LINUX_SYS_linux_newfstatat
162 	case LINUX_SYS_linux_newfstatat:
163 #endif
164 #ifdef LINUX_SYS_linux_fstatat64
165 	case LINUX_SYS_linux_fstatat64:
166 #endif
167 	case LINUX_SYS_linux_utimensat:
168 		print_number(ip, narg, c);
169 		print_number(ip, narg, c);
170 		break;
171 	case LINUX_SYS_linux_unlinkat:
172 		print_number(ip, narg, c);
173 		break;
174 	case LINUX_SYS_linux_clock_gettime:
175 	case LINUX_SYS_linux_clock_settime:
176 	case LINUX_SYS_linux_clock_getres:
177 	case LINUX_SYS_linux_timer_create:
178 		putchar('(');
179 		sysdecode_linux_clockid(stdout, *ip);
180 		c = ',';
181 		ip++;
182 		narg--;
183 		break;
184 	case LINUX_SYS_linux_clock_nanosleep:
185 		putchar('(');
186 		sysdecode_linux_clockid(stdout, *ip);
187 		putchar(',');
188 		ip++;
189 		narg--;
190 		print_mask_arg0(sysdecode_linux_clock_flags, *ip);
191 		c = ',';
192 		ip++;
193 		narg--;
194 		break;
195 	case LINUX_SYS_linux_kill:
196 	case LINUX_SYS_linux_tkill:
197 	case LINUX_SYS_linux_rt_sigqueueinfo:
198 		print_number(ip, narg, c);
199 		putchar(',');
200 		print_linux_signal(*ip);
201 		ip++;
202 		narg--;
203 		break;
204 	case LINUX_SYS_linux_tgkill:
205 	case LINUX_SYS_linux_rt_tgsigqueueinfo:
206 		print_number(ip, narg, c);
207 		print_number(ip, narg, c);
208 		putchar(',');
209 		print_linux_signal(*ip);
210 		ip++;
211 		narg--;
212 		break;
213 #ifdef LINUX_SYS_linux_open
214 	case LINUX_SYS_linux_open:
215 #endif
216 	case LINUX_SYS_linux_openat:
217 		print_number(ip, narg, c);
218 		putchar(',');
219 		print_mask_arg(sysdecode_linux_open_flags, ip[0]);
220 		if ((ip[0] & LINUX_O_CREAT) == LINUX_O_CREAT) {
221 			putchar(',');
222 			decode_filemode(ip[1]);
223 		}
224 		ip += 2;
225 		narg -= 2;
226 		break;
227 	case LINUX_SYS_linux_rt_sigaction:
228 		putchar('(');
229 		print_linux_signal(*ip);
230 		ip++;
231 		narg--;
232 		c = ',';
233 		break;
234 	case LINUX_SYS_linux_ftruncate:
235 	case LINUX_SYS_linux_truncate:
236 		print_number(ip, narg, c);
237 		print_number64(first, ip, narg, c);
238 		break;
239 	case LINUX_SYS_linux_getitimer:
240 	case LINUX_SYS_linux_setitimer:
241 		putchar('(');
242 		print_integer_arg(sysdecode_itimer, *ip);
243 		ip++;
244 		narg--;
245 		c = ',';
246 		break;
247 	case LINUX_SYS_linux_rt_sigprocmask:
248 #ifdef LINUX_SYS_linux_sigprocmask
249 	case LINUX_SYS_linux_sigprocmask:
250 #endif
251 		putchar('(');
252 		print_integer_arg(sysdecode_linux_sigprocmask_how, *ip);
253 		ip++;
254 		narg--;
255 		c = ',';
256 		break;
257 	}
258 	switch (ktr->ktr_code) {
259 	case LINUX_SYS_linux_fchownat:
260 	case LINUX_SYS_linux_faccessat:
261 	case LINUX_SYS_linux_fchmodat:
262 #ifdef LINUX_SYS_linux_newfstatat
263 	case LINUX_SYS_linux_newfstatat:
264 #endif
265 #ifdef LINUX_SYS_linux_fstatat64
266 	case LINUX_SYS_linux_fstatat64:
267 #endif
268 	case LINUX_SYS_linux_linkat:
269 	case LINUX_SYS_linux_unlinkat:
270 	case LINUX_SYS_linux_utimensat:
271 		putchar(',');
272 		print_mask_arg0(sysdecode_linux_atflags, *ip);
273 		ip++;
274 		narg--;
275 		break;
276 	}
277 	*resc = c;
278 	*resip = ip;
279 	*resnarg = narg;
280 }
281 
282 #if defined(__amd64__)
283 void
284 ktrsyscall_linux32(struct ktr_syscall *ktr, register_t **resip,
285     int *resnarg, char *resc)
286 {
287 	int narg = ktr->ktr_narg;
288 	register_t *ip, *first;
289 	int quad_align, quad_slots;
290 	char c;
291 
292 	ip = first = &ktr->ktr_args[0];
293 	c = *resc;
294 	quad_align = 0;
295 	quad_slots = 2;
296 	switch (ktr->ktr_code) {
297 	case LINUX32_SYS_linux_faccessat:
298 	case LINUX32_SYS_linux_fchmodat:
299 	case LINUX32_SYS_linux_fchownat:
300 	case LINUX32_SYS_linux_fstatat64:
301 	case LINUX32_SYS_linux_futimesat:
302 	case LINUX32_SYS_linux_linkat:
303 	case LINUX32_SYS_linux_mkdirat:
304 	case LINUX32_SYS_linux_mknodat:
305 	case LINUX32_SYS_linux_openat:
306 	case LINUX32_SYS_linux_readlinkat:
307 	case LINUX32_SYS_linux_renameat:
308 	case LINUX32_SYS_linux_unlinkat:
309 	case LINUX32_SYS_linux_utimensat:
310 		putchar('(');
311 		print_integer_arg_valid(sysdecode_atfd, *ip);
312 		c = ',';
313 		ip++;
314 		narg--;
315 		break;
316 	}
317 	switch (ktr->ktr_code) {
318 	case LINUX32_SYS_linux_access:
319 	case LINUX32_SYS_linux_faccessat:
320 		print_number(ip, narg, c);
321 		putchar(',');
322 		print_mask_arg(sysdecode_access_mode, *ip);
323 		ip++;
324 		narg--;
325 		break;
326 	case LINUX32_SYS_linux_chmod:
327 	case LINUX32_SYS_fchmod:
328 	case LINUX32_SYS_linux_fchmodat:
329 		print_number(ip, narg, c);
330 		putchar(',');
331 		decode_filemode(*ip);
332 		ip++;
333 		narg--;
334 		break;
335 	case LINUX32_SYS_linux_mknodat:
336 		print_number(ip, narg, c);
337 		putchar(',');
338 		decode_filemode(*ip);
339 		ip++;
340 		narg--;
341 		break;
342 	case LINUX32_SYS_linux_mkdir:
343 	case LINUX32_SYS_linux_mkdirat:
344 		print_number(ip, narg, c);
345 		putchar(',');
346 		decode_filemode(*ip);
347 		ip++;
348 		narg--;
349 		break;
350 	case LINUX32_SYS_linux_linkat:
351 	case LINUX32_SYS_linux_renameat:
352 	case LINUX32_SYS_linux_symlinkat:
353 		print_number(ip, narg, c);
354 		putchar(',');
355 		print_integer_arg_valid(sysdecode_atfd, *ip);
356 		ip++;
357 		narg--;
358 		print_number(ip, narg, c);
359 		break;
360 	case LINUX32_SYS_linux_fchownat:
361 		print_number(ip, narg, c);
362 		print_number(ip, narg, c);
363 		print_number(ip, narg, c);
364 		break;
365 	case LINUX32_SYS_linux_fstatat64:
366 	case LINUX32_SYS_linux_utimensat:
367 		print_number(ip, narg, c);
368 		print_number(ip, narg, c);
369 		break;
370 	case LINUX32_SYS_linux_unlinkat:
371 		print_number(ip, narg, c);
372 		break;
373 	case LINUX32_SYS_linux_clock_gettime:
374 	case LINUX32_SYS_linux_clock_settime:
375 	case LINUX32_SYS_linux_clock_getres:
376 	case LINUX32_SYS_linux_timer_create:
377 	case LINUX32_SYS_linux_clock_gettime64:
378 	case LINUX32_SYS_linux_clock_settime64:
379 	case LINUX32_SYS_linux_clock_getres_time64:
380 		putchar('(');
381 		sysdecode_linux_clockid(stdout, *ip);
382 		c = ',';
383 		ip++;
384 		narg--;
385 		break;
386 	case LINUX32_SYS_linux_clock_nanosleep:
387 		putchar('(');
388 		sysdecode_linux_clockid(stdout, *ip);
389 		putchar(',');
390 		ip++;
391 		narg--;
392 		print_mask_arg0(sysdecode_linux_clock_flags, *ip);
393 		c = ',';
394 		ip++;
395 		narg--;
396 		break;
397 	case LINUX32_SYS_linux_kill:
398 	case LINUX32_SYS_linux_tkill:
399 	case LINUX32_SYS_linux_rt_sigqueueinfo:
400 		print_number(ip, narg, c);
401 		putchar(',');
402 		print_linux_signal(*ip);
403 		ip++;
404 		narg--;
405 		break;
406 	case LINUX32_SYS_linux_tgkill:
407 	case LINUX32_SYS_linux_rt_tgsigqueueinfo:
408 		print_number(ip, narg, c);
409 		print_number(ip, narg, c);
410 		putchar(',');
411 		print_linux_signal(*ip);
412 		ip++;
413 		narg--;
414 		break;
415 	case LINUX32_SYS_linux_open:
416 	case LINUX32_SYS_linux_openat:
417 		print_number(ip, narg, c);
418 		putchar(',');
419 		print_mask_arg(sysdecode_linux_open_flags, ip[0]);
420 		if ((ip[0] & LINUX_O_CREAT) == LINUX_O_CREAT) {
421 			putchar(',');
422 			decode_filemode(ip[1]);
423 		}
424 		ip += 2;
425 		narg -= 2;
426 		break;
427 	case LINUX32_SYS_linux_signal:
428 	case LINUX32_SYS_linux_sigaction:
429 	case LINUX32_SYS_linux_rt_sigaction:
430 		putchar('(');
431 		print_linux_signal(*ip);
432 		ip++;
433 		narg--;
434 		c = ',';
435 		break;
436 	case LINUX32_SYS_linux_ftruncate:
437 	case LINUX32_SYS_linux_truncate:
438 		print_number(ip, narg, c);
439 		print_number64(first, ip, narg, c);
440 		break;
441 	case LINUX32_SYS_linux_getitimer:
442 	case LINUX32_SYS_linux_setitimer:
443 		putchar('(');
444 		print_integer_arg(sysdecode_itimer, *ip);
445 		ip++;
446 		narg--;
447 		c = ',';
448 		break;
449 	case LINUX32_SYS_linux_rt_sigprocmask:
450 	case LINUX32_SYS_linux_sigprocmask:
451 		putchar('(');
452 		print_integer_arg(sysdecode_linux_sigprocmask_how, *ip);
453 		ip++;
454 		narg--;
455 		c = ',';
456 		break;
457 	}
458 	switch (ktr->ktr_code) {
459 	case LINUX32_SYS_linux_fchownat:
460 	case LINUX32_SYS_linux_faccessat:
461 	case LINUX32_SYS_linux_fchmodat:
462 	case LINUX32_SYS_linux_fstatat64:
463 	case LINUX32_SYS_linux_linkat:
464 	case LINUX32_SYS_linux_unlinkat:
465 	case LINUX32_SYS_linux_utimensat:
466 		putchar(',');
467 		print_mask_arg0(sysdecode_linux_atflags, *ip);
468 		ip++;
469 		narg--;
470 		break;
471 	}
472 	*resc = c;
473 	*resip = ip;
474 	*resnarg = narg;
475 }
476 #endif /* __amd64__ */
477 
478 static void
479 ktrsigset(const char *name, const l_sigset_t *mask, size_t sz)
480 {
481 	unsigned long i, c;
482 
483 	printf("%s [ ", name);
484 	c = 0;
485 	for (i = 1; i <= sz * CHAR_BIT; i++) {
486 		if (!LINUX_SIGISMEMBER(*mask, i))
487 			continue;
488 		if (c != 0)
489 			printf(", ");
490 		printf("%s", sysdecode_linux_signal(i));
491 		c++;
492 	}
493 	if (c == 0)
494 		printf("empty ]\n");
495 	else
496 		printf(" ]\n");
497 }
498 
499 bool
500 ktrstruct_linux(const char *name, const char *data, size_t datalen)
501 {
502 	l_sigset_t mask;
503 
504 	if (strcmp(name, "l_sigset_t") == 0) {
505 		/* Old Linux sigset_t is one word size. */
506 		if (datalen < sizeof(int) || datalen > sizeof(l_sigset_t))
507 			return (false);
508 		memcpy(&mask, data, datalen);
509 		ktrsigset(name, &mask, datalen);
510 	} else
511 		return (false);
512 
513 	return (true);
514 }
515