xref: /dragonfly/usr.bin/kdump/mksubr (revision a705726d)
1#!/bin/sh
2#
3# Generates kdump_subr.c
4# mkioctls is a special-purpose script, and works fine as it is
5# now, so it remains independent. The idea behind how it generates
6# its list was heavily borrowed here.
7#
8# Some functions here are automatically generated. This can mean
9# the user will see unusual kdump output or errors while building
10# if the underlying .h files are changed significantly.
11#
12# Key:
13# AUTO: Completely auto-generated with either the "or" or the "switch"
14# method.
15# AUTO - Special: Generated automatically, but with some extra commands
16# that the auto_*_type() functions are inappropriate for.
17# MANUAL: Manually entered and must therefore be manually updated.
18
19# $FreeBSD: src/usr.bin/kdump/mksubr,v 1.9 2007/04/09 19:16:24 emaste Exp $
20
21set -e
22
23LC_ALL=C; export LC_ALL
24
25if [ -z "$1" ]
26then
27	echo "usage: sh $0 include-dir"
28	exit 1
29fi
30include_dir=$1
31
32#
33# Automatically generates a C function that will print out the
34# numeric input as a pipe-delimited string of the appropriate
35# #define keys. ex:
36# S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
37# The XOR is necessary to prevent including the "0"-value in every
38# line.
39#
40auto_or_int () {
41	local name grep file
42	name=$1
43	grep=$2
44	file=$3
45
46	cat <<_EOF_
47/* AUTO */
48void
49$name (int arg)
50{
51	bool	or = false;
52	printf("%#x<", arg);
53_EOF_
54	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
55		$include_dir/$file | \
56	awk '{ for (i = 1; i <= NF; i++) \
57		if ($i ~ /define/) \
58			break; \
59		++i; \
60		printf "\tif(!((arg>0)^((%s)>0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }'
61cat <<_EOF_
62	printf(">");
63	if (or == false)
64		printf("<invalid>%d", arg);
65}
66
67_EOF_
68}
69
70#
71# Automatically generates a C function that will print out the
72# numeric input as a pipe-delimited string of the appropriate
73# #define keys. ex:
74# S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
75# The XOR is necessary to prevent including the "0"-value in every
76# line.
77#
78auto_or_long () {
79	local name grep file
80	name=$1
81	grep=$2
82	file=$3
83
84	cat <<_EOF_
85/* AUTO */
86void
87$name (long arg)
88{
89	bool	or = false;
90	printf("%#lx<", arg);
91_EOF_
92	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
93		$include_dir/$file | \
94	awk '{ for (i = 1; i <= NF; i++) \
95		if ($i ~ /define/) \
96			break; \
97		++i; \
98		printf "\tif(!((arg>0)^((%s)>0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }'
99cat <<_EOF_
100	printf(">");
101	if (or == false)
102		printf("<invalid>%ld", arg);
103}
104
105_EOF_
106}
107
108#
109# Automatically generates a C function used when the argument
110# maps to a single, specific #definition
111#
112auto_switch_type () {
113	local name grep file noinvdef
114	name=$1
115	grep=$2
116	file=$3
117	noinvdef=$4
118
119	cat <<_EOF_
120/* AUTO */
121void
122$name (int arg)
123{
124	switch (arg) {
125_EOF_
126	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
127		$include_dir/$file | \
128	awk '{ for (i = 1; i <= NF; i++) \
129		if ($i ~ /define/) \
130			break; \
131		++i; \
132		printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }'
133	if [ -z "$noinvdef" ]; then
134cat <<_EOF_
135	default: /* Should not reach */
136		printf("<invalid=%ld>", (long)arg);
137	}
138}
139
140_EOF_
141	else
142cat <<_EOF_
143	default:
144		printf("%ld", (long)arg);
145	}
146}
147
148_EOF_
149	fi
150}
151
152#
153# Automatically generates a C function used when the argument
154# maps to a #definition
155#
156auto_if_type () {
157	local name grep file
158	name=$1
159	grep=$2
160	file=$3
161
162	cat <<_EOF_
163/* AUTO */
164void
165$name (int arg)
166{
167_EOF_
168	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
169		$include_dir/$file | \
170	awk '{ printf "\t"; \
171		if (NR > 1) \
172			printf "else " ; \
173		printf "if (arg == %s) \n\t\tprintf(\"%s\");\n", $2, $2 }'
174cat <<_EOF_
175	else /* Should not reach */
176		printf("<invalid=%ld>", (long)arg);
177}
178
179_EOF_
180}
181
182# C start
183
184cat <<_EOF_
185#define _KERNEL_STRUCTURES
186
187#include <stdio.h>
188#include <time.h>
189#include <sys/fcntl.h>
190#include <sys/stat.h>
191#include <sys/unistd.h>
192#include <sys/mman.h>
193#include <sys/wait.h>
194#include <sys/socket.h>
195#include <netinet/in.h>
196#include <sys/param.h>
197#include <sys/mount.h>
198#include <sys/resource.h>
199#include <sys/reboot.h>
200#include <sched.h>
201#include <sys/usched.h>
202#include <sys/linker.h>
203#include <sys/extattr.h>
204#include <sys/acl.h>
205#include <aio.h>
206#include <sys/sem.h>
207#include <sys/ipc.h>
208#include <sys/rtprio.h>
209#include <sys/shm.h>
210#include <vfs/ufs/quota.h>
211#include <sys/kenv.h>
212#include <sys/checkpoint.h>
213#include <sys/procctl.h>
214#include <sys/mountctl.h>
215#include <sys/varsym.h>
216
217#include "kdump_subr.h"
218
219/*
220 * These are simple support macros. print_or utilizes a variable
221 * defined in the calling function to track whether or not it should
222 * print a logical-OR character ('|') before a string. if_print_or
223 * simply handles the necessary "if" statement used in many lines
224 * of this file.
225 */
226#define print_or(str,orflag) do {                  \\
227	if (orflag) putchar('|'); else orflag = true; \\
228	printf (str); }                            \\
229	while (0)
230#define if_print_or(i,flag,orflag) do {            \\
231	if ((i & flag) == flag)                    \\
232	print_or(#flag,orflag); }                  \\
233	while (0)
234
235/* MANUAL */
236extern char *signames[]; /* from kdump.c */
237void
238signame (int sig)
239{
240	if (sig > 0 && sig < NSIG && signames[sig] != NULL)
241		printf("SIG%s",signames[sig]);
242	else
243		printf("SIG %d", sig);
244}
245
246/* MANUAL */
247void
248semctlname (int cmd)
249{
250	switch (cmd) {
251	case GETNCNT:
252		printf("GETNCNT");
253		break;
254	case GETPID:
255		printf("GETPID");
256		break;
257	case GETVAL:
258		printf("GETVAL");
259		break;
260	case GETALL:
261		printf("GETALL");
262		break;
263	case GETZCNT:
264		printf("GETZCNT");
265		break;
266	case SETVAL:
267		printf("SETVAL");
268		break;
269	case SETALL:
270		printf("SETALL");
271		break;
272	case IPC_RMID:
273		printf("IPC_RMID");
274		break;
275	case IPC_SET:
276		printf("IPC_SET");
277		break;
278	case IPC_STAT:
279		printf("IPC_STAT");
280		break;
281	default: /* Should not reach */
282		printf("<invalid=%ld>", (long)cmd);
283	}
284}
285
286/* MANUAL */
287void
288shmctlname (int cmd) {
289	switch (cmd) {
290	case IPC_RMID:
291		printf("IPC_RMID");
292		break;
293	case IPC_SET:
294		printf("IPC_SET");
295		break;
296	case IPC_STAT:
297		printf("IPC_STAT");
298		break;
299	default: /* Should not reach */
300		printf("<invalid=%ld>", (long)cmd);
301	}
302}
303
304/* MANUAL */
305void
306semgetname (int flag) {
307	int	or = 0;
308	if_print_or(flag, SEM_R, or);
309	if_print_or(flag, SEM_A, or);
310	if_print_or(flag, (SEM_R>>3), or);
311	if_print_or(flag, (SEM_A>>3), or);
312	if_print_or(flag, (SEM_R>>6), or);
313	if_print_or(flag, (SEM_A>>6), or);
314}
315
316/*
317 * MANUAL
318 *
319 * Only used by SYS_open. Unless O_CREAT is set in flags, the
320 * mode argument is unused (and often bogus and misleading).
321 */
322void
323flagsandmodename (int flags, int mode, int decimal) {
324	flagsname (flags);
325	putchar(',');
326	if ((flags & O_CREAT) == O_CREAT) {
327		modename (mode);
328	} else {
329		if (decimal) {
330			printf("<unused>%ld", (long)mode);
331		} else {
332			printf("<unused>%#lx", (long)mode);
333		}
334	}
335}
336
337/*
338 * MANUAL
339 *
340 * [g|s]etsockopt's level argument can either be SOL_SOCKET or a value
341 * referring to a line in /etc/protocols . It might be appropriate
342 * to use getprotoent(3) here.
343 */
344void
345sockoptlevelname (int level, int decimal)
346{
347	if (level == SOL_SOCKET) {
348		printf("SOL_SOCKET");
349	} else {
350		if (decimal) {
351			printf("%ld", (long)level);
352		} else {
353			printf("%#lx", (long)level);
354		}
355	}
356}
357
358_EOF_
359
360auto_or_int "modename" "S_[A-Z]+[[:space:]]+[0-6]{7}" "sys/stat.h"
361auto_or_int "flagsname" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h"
362auto_or_int "accessmodename" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h"
363auto_or_int "mmapprotname" "PROT_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h"
364auto_or_int "mmapflagsname" "MAP_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h"
365auto_or_int "wait4optname" "W[A-Z]+[[:space:]]+[0-9]+" "sys/wait.h"
366auto_or_int "getfsstatflagsname" "MNT_[A-Z]+[[:space:]]+0x[0-9][0-9][0-9][0-9][^0-9]" "sys/mount.h"
367auto_or_int "mountflagsname" "MNT_[A-Z]+[[:space:]]+0x[0-9][0-9][0-9][0-9][0-9]+" "sys/mount.h"
368auto_or_int "rebootoptname" "RB_[A-Z]+[[:space:]]+0x[0-9]+" "sys/reboot.h"
369auto_or_int "flockname" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h"
370auto_or_int "mlockallname" "MCL_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h"
371auto_or_int "shmatname" "SHM_[A-Z]+[[:space:]]+[0-9]{6}+" "sys/shm.h"
372auto_or_int "rforkname" "RF[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h"
373auto_or_long "chflagsname" "[SU]F_[A-Z]+[[:space:]]+0x[0-9]+" "sys/stat.h"
374auto_or_int "atflagsname" "AT_[A-Z_]+[[:space:]]+[1-9]+[0-9]*" "sys/fcntl.h"
375
376auto_switch_type "whencename" "SEEK_[A-Z]+[[:space:]]+[0-9]+" "sys/unistd.h"
377auto_switch_type "rlimitname" "RLIMIT_[A-Z]+[[:space:]]+[0-9]+" "sys/resource.h"
378auto_switch_type "shutdownhowname" "SHUT_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h"
379auto_switch_type "prioname" "PRIO_[A-Z]+[[:space:]]+[0-9]" "sys/resource.h"
380auto_switch_type "madvisebehavname" "_?MADV_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h"
381auto_switch_type "msyncflagsname" "MS_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h"
382auto_switch_type "schedpolicyname" "SCHED_[A-Z]+[[:space:]]+[0-9]+" "sched.h"
383auto_switch_type "extattrctlname" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h"
384auto_switch_type "kldsymcmdname" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
385auto_switch_type "sendfileflagsname" "SF_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h"
386auto_switch_type "acltypename" "ACL_TYPE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/acl.h"
387auto_switch_type "sigprocmaskhowname" "SIG_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h"
388auto_switch_type "lio_listioname" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h"
389auto_switch_type "minheritname" "INHERIT_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h"
390auto_switch_type "quotactlname" "Q_[A-Z]+[[:space:]]+0x[0-9]+" "ufs/ufs/quota.h"
391auto_if_type "sockdomainname" "PF_[[:alnum:]]+[[:space:]]+" "sys/socket.h"
392auto_if_type "sockipprotoname" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h"
393auto_switch_type "sockoptname" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h"
394auto_switch_type "socktypename" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h"
395auto_switch_type "clockidname" "CLOCK_[[:alnum:]]+" "time.h" "noinvdef"
396auto_switch_type "pathconfname" "_PC_[[:alnum:]]+" "sys/unistd.h"
397auto_switch_type "uschedcmdname" "USCHED_[[:alnum:]]+" "sys/usched.h"
398auto_switch_type "ckpttypename" "CKPT_[[:alnum:]]+" "sys/checkpoint.h"
399auto_switch_type "procctlcmdname" "PROC_[[:alnum:]]+" "sys/procctl.h"
400auto_switch_type "mountctlopname" "MOUNTCTL_[[:alnum:]]+" "sys/mountctl.h"
401auto_switch_type "varsymlvlname" "VARSYM_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/varsym.h"
402
403cat <<_EOF_
404/*
405 * AUTO - Special
406 * F_ is used to specify fcntl commands as well as arguments. Both sets are
407 * grouped in fcntl.h, and this awk script grabs the first group.
408 */
409void
410fcntlcmdname (int cmd, int arg, int decimal)
411{
412	switch (cmd) {
413_EOF_
414egrep "^#[[:space:]]*define[[:space:]]+F_[A-Z0-9_]+[[:space:]]+[0-9]+[[:space:]]*" \
415	$include_dir/sys/fcntl.h | \
416	awk 'BEGIN { o=0 } { for (i = 1; i <= NF; i++) \
417		if ($i ~ /define/) \
418			break; \
419		++i; \
420		if (o <= $(i+1)) \
421			printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i; \
422		else \
423			exit; \
424		o = $(i+1) }'
425cat <<_EOF_
426	default: /* Should not reach */
427		printf("<invalid=%ld>", (long)cmd);
428	}
429	putchar(',');
430	if (cmd == F_GETFD || cmd == F_SETFD) {
431		if (arg == FD_CLOEXEC)
432			printf("FD_CLOEXEC");
433		else if (arg == 0)
434			printf("0");
435		else {
436			if (decimal)
437				printf("<invalid>%ld", (long)arg);
438			else
439				printf("<invalid>%#lx", (long)arg);
440		}
441	} else if (cmd == F_SETFL) {
442		flagsname(arg);
443	} else {
444		if (decimal)
445			printf("%ld", (long)arg);
446		else
447			printf("%#lx", (long)arg);
448	}
449}
450
451/*
452 * AUTO - Special
453 *
454 * The only reason this is not fully automated is due to the
455 * grep -v RTP_PRIO statement. A better egrep line should
456 * make this capable of being a auto_switch_type() function.
457 */
458void
459rtprioname (int func)
460{
461	switch (func) {
462_EOF_
463egrep "^#[[:space:]]*define[[:space:]]+RTP_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" \
464	$include_dir/sys/rtprio.h | grep -v RTP_PRIO | \
465	awk '{ for (i = 1; i <= NF; i++) \
466		if ($i ~ /define/) \
467			break; \
468		++i; \
469		printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }'
470cat <<_EOF_
471	default: /* Should not reach */
472		printf("<invalid=%ld>", (long)func);
473	}
474}
475
476/*
477 * AUTO - Special
478 *
479 * The send and recv functions have a flags argument which can be
480 * set to 0. There is no corresponding #define. The auto_ functions
481 * detect this as "invalid", which is incorrect here.
482 */
483void
484sendrecvflagsname (int flags)
485{
486	int	or = 0;
487
488	if (flags == 0) {
489		printf("0");
490		return;
491	}
492
493	printf("%#x<", flags);
494_EOF_
495egrep "^#[[:space:]]*define[[:space:]]+MSG_[A-Z_]+[[:space:]]+0x[0-9]+[[:space:]]*" $include_dir/sys/socket.h | \
496	awk '{ for (i = 1; i <= NF; i++) \
497		if ($i ~ /define/) \
498			break; \
499		++i; \
500		printf "\tif(!((flags>0)^((%s)>0)))\n\t\tif_print_or(flags, %s, or);\n", $i, $i }'
501cat <<_EOF_
502	printf(">");
503}
504
505/*
506 * AUTO - Special
507 *
508 * The only reason this is not fully automated is due to the
509 * grep -vw ... statement. A better egrep line should
510 * make this capable of being a auto_switch_type() function.
511 */
512void
513kenvactname (int act)
514{
515	switch (act) {
516_EOF_
517egrep "^#[[:space:]]*define[[:space:]]+KENV_[A-Z]+[[:space:]]+[0-9]+[[:space:]]*" \
518	$include_dir/sys/kenv.h | grep -vw -e KENV_MNAMELEN -e KENV_MVALLEN | \
519	awk '{ for (i = 1; i <= NF; i++) \
520		if ($i ~ /define/) \
521			break; \
522		++i; \
523		printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }'
524cat <<_EOF_
525	default: /* Should not reach */
526		printf("<invalid=%ld>", (long)act);
527	}
528}
529_EOF_
530