[BACK]Return to mksubr CVS log [TXT][DIR] Up to [local] / src / usr.bin / kdump

File: [local] / src / usr.bin / kdump / mksubr (download)

Revision 1.1, Thu Jun 16 17:05:38 2011 UTC (12 years, 11 months ago) by otto
Branch: MAIN

mksubr from freebsd, to be used to generate flags to name translation
for kdump.  Added missing license to the file, with the kind
permission of the author David Kirchner. Not used yet. ok miod@

#!/bin/sh
# $OpenBSD: mksubr,v 1.1 2011/06/16 17:05:38 otto Exp $
#
# Copyright (c) 2006 David Kirchner <dpk@dpk.net>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# $FreeBSD: src/usr.bin/kdump/mksubr,v 1.17 2011/06/06 19:00:38 dchagin Exp $
#
# Generates kdump_subr.c
# mkioctls is a special-purpose script, and works fine as it is
# now, so it remains independent. The idea behind how it generates
# its list was heavily borrowed here.
#
# Some functions here are automatically generated. This can mean
# the user will see unusual kdump output or errors while building
# if the underlying .h files are changed significantly.
#
# Key:
# AUTO: Completely auto-generated with either the "or" or the "switch"
# method.
# AUTO - Special: Generated automatically, but with some extra commands
# that the auto_*_type() functions are inappropriate for.
# MANUAL: Manually entered and must therefore be manually updated.

set -e

LC_ALL=C; export LC_ALL

if [ -z "$1" ]
then
	echo "usage: sh $0 include-dir"
	exit 1
fi
include_dir=$1

#
# Automatically generates a C function that will print out the
# numeric input as a pipe-delimited string of the appropriate
# #define keys. ex:
# S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
# The XOR is necessary to prevent including the "0"-value in every
# line.
#
auto_or_type () {
	local name grep file
	name=$1
	grep=$2
	file=$3

	cat <<_EOF_
/* AUTO */
void
$name (int arg)
{
	int	or = 0;
	printf("%#x<", arg);
_EOF_
	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
		$include_dir/$file | \
	awk '{ for (i = 1; i <= NF; i++) \
		if ($i ~ /define/) \
			break; \
		++i; \
		printf "\tif(!((arg>0)^((%s)>0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }'
cat <<_EOF_
	printf(">");
	if (or == 0)
		(void)printf("<invalid>%ld", (long)arg);
}

_EOF_
}

#
# Automatically generates a C function used when the argument
# maps to a single, specific #definition
#
auto_switch_type () {
	local name grep file
	name=$1
	grep=$2
	file=$3

	cat <<_EOF_
/* AUTO */
void
$name (int arg)
{
	switch (arg) {
_EOF_
	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
		$include_dir/$file | \
	awk '{ for (i = 1; i <= NF; i++) \
		if ($i ~ /define/) \
			break; \
		++i; \
		printf "\tcase %s:\n\t\t(void)printf(\"%s\");\n\t\tbreak;\n", $i, $i }'
cat <<_EOF_
	default: /* Should not reach */
		(void)printf("<invalid=%ld>", (long)arg);
	}
}

_EOF_
}

#
# Automatically generates a C function used when the argument
# maps to a #definition
#
auto_if_type () {
	local name grep file
	name=$1
	grep=$2
	file=$3

	cat <<_EOF_
/* AUTO */
void
$name (int arg)
{
_EOF_
	egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \
		$include_dir/$file | \
	awk '{ printf "\t"; \
		if (NR > 1) \
			printf "else " ; \
		printf "if (arg == %s) \n\t\tprintf(\"%s\");\n", $2, $2 }'
cat <<_EOF_
	else /* Should not reach */
		(void)printf("<invalid=%ld>", (long)arg);
}

_EOF_
}

# C start

cat <<_EOF_
#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#define _KERNEL
#include <sys/socket.h>
#undef _KERNEL
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/reboot.h>
#include <sched.h>
#include <sys/linker.h>
#define _KERNEL
#include <sys/thr.h>
#undef _KERNEL
#include <sys/extattr.h>
#include <sys/acl.h>
#include <aio.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/rtprio.h>
#include <sys/shm.h>
#include <nfsserver/nfs.h>
#include <ufs/ufs/quota.h>

#include "kdump_subr.h"

/*
 * These are simple support macros. print_or utilizes a variable
 * defined in the calling function to track whether or not it should
 * print a logical-OR character ('|') before a string. if_print_or
 * simply handles the necessary "if" statement used in many lines
 * of this file.
 */
#define print_or(str,orflag) do {                  \\
	if (orflag) putchar('|'); else orflag = 1; \\
	printf (str); }                            \\
	while (0)
#define if_print_or(i,flag,orflag) do {            \\
	if ((i & flag) == flag)                    \\
	print_or(#flag,orflag); }                  \\
	while (0)

/* MANUAL */
extern char *signames[]; /* from kdump.c */
void
signame (int sig)
{
	if (sig > 0 && sig < NSIG)
		(void)printf("SIG%s",signames[sig]);
	else
		(void)printf("SIG %d", sig);
}

/* MANUAL */
void
semctlname (int cmd)
{
	switch (cmd) {
	case GETNCNT:
		(void)printf("GETNCNT");
		break;
	case GETPID:
		(void)printf("GETPID");
		break;
	case GETVAL:
		(void)printf("GETVAL");
		break;
	case GETALL:
		(void)printf("GETALL");
		break;
	case GETZCNT:
		(void)printf("GETZCNT");
		break;
	case SETVAL:
		(void)printf("SETVAL");
		break;
	case SETALL:
		(void)printf("SETALL");
		break;
	case IPC_RMID:
		(void)printf("IPC_RMID");
		break;
	case IPC_SET:
		(void)printf("IPC_SET");
		break;
	case IPC_STAT:
		(void)printf("IPC_STAT");
		break;
	default: /* Should not reach */
		(void)printf("<invalid=%ld>", (long)cmd);
	}
}

/* MANUAL */
void
shmctlname (int cmd) {
	switch (cmd) {
	case IPC_RMID:
		(void)printf("IPC_RMID");
		break;
	case IPC_SET:
		(void)printf("IPC_SET");
		break;
	case IPC_STAT:
		(void)printf("IPC_STAT");
		break;
	default: /* Should not reach */
		(void)printf("<invalid=%ld>", (long)cmd);
	}
}

/* MANUAL */
void
semgetname (int flag) {
	int	or = 0;
	if_print_or(flag, IPC_CREAT, or);
	if_print_or(flag, IPC_EXCL, or);
	if_print_or(flag, SEM_R, or);
	if_print_or(flag, SEM_A, or);
	if_print_or(flag, (SEM_R>>3), or);
	if_print_or(flag, (SEM_A>>3), or);
	if_print_or(flag, (SEM_R>>6), or);
	if_print_or(flag, (SEM_A>>6), or);
}

/*
 * MANUAL
 *
 * Only used by SYS_open. Unless O_CREAT is set in flags, the
 * mode argument is unused (and often bogus and misleading).
 */
void
flagsandmodename (int flags, int mode, int decimal) {
	flagsname (flags);
	(void)putchar(',');
	if ((flags & O_CREAT) == O_CREAT) {
		modename (mode);
	} else {
		if (decimal) {
			(void)printf("<unused>%ld", (long)mode);
		} else {
			(void)printf("<unused>%#lx", (long)mode);
		}
	}
}

/*
 * MANUAL
 *
 * [g|s]etsockopt's level argument can either be SOL_SOCKET or a value
 * referring to a line in /etc/protocols . It might be appropriate
 * to use getprotoent(3) here.
 */
void
sockoptlevelname (int level, int decimal)
{
	if (level == SOL_SOCKET) {
		(void)printf("SOL_SOCKET");
	} else {
		if (decimal) {
			(void)printf("%ld", (long)level);
		} else {
			(void)printf("%#lx", (long)level);
		}
	}
}

_EOF_

auto_or_type "modename" "S_[A-Z]+[[:space:]]+[0-6]{7}" "sys/stat.h"
auto_or_type "flagsname" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h"
auto_or_type "accessmodename" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h"
auto_or_type "mmapprotname" "PROT_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h"
auto_or_type "mmapflagsname" "MAP_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h"
auto_or_type "wait4optname" "W[A-Z]+[[:space:]]+[0-9]+" "sys/wait.h"
auto_or_type "getfsstatflagsname" "MNT_[A-Z]+[[:space:]]+[1-9][0-9]*" "sys/mount.h"
auto_or_type "mountflagsname" "MNT_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mount.h"
auto_or_type "rebootoptname" "RB_[A-Z]+[[:space:]]+0x[0-9]+" "sys/reboot.h"
auto_or_type "flockname" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h"
auto_or_type "thrcreateflagsname" "THR_[A-Z]+[[:space:]]+0x[0-9]+" "sys/thr.h"
auto_or_type "mlockallname" "MCL_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h"
auto_or_type "shmatname" "SHM_[A-Z]+[[:space:]]+[0-9]{6}+" "sys/shm.h"
auto_or_type "rforkname" "RF[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h"
auto_or_type "nfssvcname" "NFSSVC_[A-Z]+[[:space:]]+0x[0-9]+" "nfsserver/nfs.h"

auto_switch_type "whencename" "SEEK_[A-Z]+[[:space:]]+[0-9]+" "sys/unistd.h"
auto_switch_type "rlimitname" "RLIMIT_[A-Z]+[[:space:]]+[0-9]+" "sys/resource.h"
auto_switch_type "shutdownhowname" "SHUT_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h"
auto_switch_type "prioname" "PRIO_[A-Z]+[[:space:]]+[0-9]" "sys/resource.h"
auto_switch_type "madvisebehavname" "_?MADV_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h"
auto_switch_type "msyncflagsname" "MS_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h"
auto_switch_type "schedpolicyname" "SCHED_[A-Z]+[[:space:]]+[0-9]+" "sched.h"
auto_switch_type "kldunloadfflagsname" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
auto_switch_type "extattrctlname" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h"
auto_switch_type "kldsymcmdname" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
auto_switch_type "sendfileflagsname" "SF_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h"
auto_switch_type "acltypename" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h"
auto_switch_type "sigprocmaskhowname" "SIG_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h"
auto_switch_type "lio_listioname" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h"
auto_switch_type "minheritname" "INHERIT_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h"
auto_switch_type "quotactlname" "Q_[A-Z]+[[:space:]]+0x[0-9]+" "ufs/ufs/quota.h"
auto_if_type "sockdomainname" "PF_[[:alnum:]]+[[:space:]]+" "sys/socket.h"
auto_if_type "sockfamilyname" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h"
auto_if_type "sockipprotoname" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h"
auto_switch_type "sockoptname" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h"
auto_switch_type "socktypename" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h"
auto_switch_type "ptraceopname" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h"

cat <<_EOF_
/*
 * AUTO - Special
 * F_ is used to specify fcntl commands as well as arguments. Both sets are
 * grouped in fcntl.h, and this awk script grabs the first group.
 */
void
fcntlcmdname (int cmd, int arg, int decimal)
{
	switch (cmd) {
_EOF_
egrep "^#[[:space:]]*define[[:space:]]+F_[A-Z]+[[:space:]]+[0-9]+[[:space:]]*" \
	$include_dir/sys/fcntl.h | \
	awk 'BEGIN { o=0 } { for (i = 1; i <= NF; i++) \
		if ($i ~ /define/) \
			break; \
		++i; \
		if (o <= $(i+1)) \
			printf "\tcase %s:\n\t\t(void)printf(\"%s\");\n\t\tbreak;\n", $i, $i; \
		else \
			exit; \
		o = $(i+1) }'
cat <<_EOF_
	default: /* Should not reach */
		(void)printf("<invalid=%ld>", (long)cmd);
	}
	(void)putchar(',');
	if (cmd == F_GETFD || cmd == F_SETFD) {
		if (arg == FD_CLOEXEC)
			(void)printf("FD_CLOEXEC");
		else if (arg == 0)
			(void)printf("0");
		else {
			if (decimal)
				(void)printf("<invalid>%ld", (long)arg);
			else
				(void)printf("<invalid>%#lx", (long)arg);
		}
	} else if (cmd == F_SETFL) {
		flagsname(arg);
	} else {
		if (decimal)
			(void)printf("%ld", (long)arg);
		else
			(void)printf("%#lx", (long)arg);
	}
}

/*
 * AUTO - Special
 *
 * The only reason this is not fully automated is due to the
 * grep -v RTP_PRIO statement. A better egrep line should
 * make this capable of being a auto_switch_type() function.
 */
void
rtprioname (int func)
{
	switch (func) {
_EOF_
egrep "^#[[:space:]]*define[[:space:]]+RTP_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" \
	$include_dir/sys/rtprio.h | grep -v RTP_PRIO | \
	awk '{ for (i = 1; i <= NF; i++) \
		if ($i ~ /define/) \
			break; \
		++i; \
		printf "\tcase %s:\n\t\t(void)printf(\"%s\");\n\t\tbreak;\n", $i, $i }'
cat <<_EOF_
	default: /* Should not reach */
		(void)printf("<invalid=%ld>", (long)func);
	}
}

/*
 * AUTO - Special
 *
 * The send and recv functions have a flags argument which can be
 * set to 0. There is no corresponding #define. The auto_ functions
 * detect this as "invalid", which is incorrect here.
 */
void
sendrecvflagsname (int flags)
{
	int	or = 0;

	if (flags == 0) {
		(void)printf("0");
		return;
	}

	printf("%#x<", flags);
_EOF_
egrep "^#[[:space:]]*define[[:space:]]+MSG_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" $include_dir/sys/socket.h | \
	awk '{ for (i = 1; i <= NF; i++) \
		if ($i ~ /define/) \
			break; \
		++i; \
		printf "\tif(!((flags>0)^((%s)>0)))\n\t\tif_print_or(flags, %s, or);\n", $i, $i }'
cat <<_EOF_
	printf(">");
}

_EOF_