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