llvm-project/compiler-rt/utils/generate_netbsd_syscalls.awk

417 lines
12 KiB
Awk
Raw Normal View History

#!/usr/bin/awk -f
#===-- generate_netbsd_syscalls.awk ----------------------------------------===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# This file is a generator of:
# - include/sanitizer/netbsd_syscall_hooks.h
# - lib/sanitizer_common/sanitizer_syscalls_netbsd.inc
#
# This script accepts on the input syscalls.master by default located in the
# /usr/src/sys/kern/syscalls.master path in the NetBSD distribution.
#
# NetBSD version 8.0.
#
#===------------------------------------------------------------------------===#
BEGIN {
# harcode the script name
script_name = "generate_netbsd_syscalls.awk"
outputh = "../include/sanitizer/netbsd_syscall_hooks.h"
outputinc = "../lib/sanitizer_common/sanitizer_syscalls_netbsd.inc"
# assert that we are in the directory with scripts
in_utils = system("test -f " script_name " && exit 1 || exit 0")
if (in_utils == 0) {
usage()
}
# assert 1 argument passed
if (ARGC != 2) {
usage()
}
# assert argument is a valid file path to syscall.master
if (system("test -f " ARGV[1]) != 0) {
usage()
}
# sanity check that the path ends with "syscall.master"
if (ARGV[1] !~ /syscalls\.master$/) {
usage()
}
# accept overloading CLANGFORMAT from environment
clangformat = "clang-format"
if ("CLANGFORMAT" in ENVIRON) {
clangformat = ENVIRON["CLANGFORMAT"]
}
# parsing specific symbols
parsingheader=1
parsedsyscalls=0
# Hardcoded in algorithm
SYS_MAXSYSARGS=8
}
# Parse the RCS ID from syscall.master
parsingheader == 1 && NR == 1 {
if (match($0, /\$[^$]+\$/)) {
# trim initial 'NetBSD: ' and trailing ' $'
syscallmasterversion = substr($0, RSTART + 9, RLENGTH - 11)
} else {
# wrong file?
usage()
}
}
# skip the following lines
# - empty
NF == 0 {
next
}
# - comment
$1 == ";" {
next
}
# separator between the header and table with syscalls
$0 == "%%" {
parsingheader = 0
next
}
# preserve 'if/elif/else/endif' C preprocessor as-is
parsingheader == 0 && $0 ~ /^#/ {
if (parsedsyscalls in ifelifelseendif) {
ifelifelseendif[parsedsyscalls] = ifelifelseendif[parsedsyscalls] "\n" $0
} else {
ifelifelseendif[parsedsyscalls] = $0
}
next
}
# parsing of syscall definitions
parsingheader == 0 && $1 ~ /^[0-9]+$/ {
# first join multiple lines into single one
while (sub(/\\$/, "")) {
getline line
$0 = $0 "" line
}
# Skip unwanted syscalls
skip=0
if ($0 ~ /OBSOL/ || $0 ~ /EXCL/ || $0 ~ /UNIMPL/) {
skip=1
}
# Compose the syscall name
# - compat?
compat=""
if (match($0, /COMPAT_[0-9]+/)) {
compat = tolower(substr($0, RSTART, RLENGTH))
}
# - alias name?
alias=""
if ($(NF) != "}" && !skip) {
alias = alias "" $(NF)
}
# - compat version?
compatver=""
if (match($0, /\|[0-9]+\|/)) {
compatver = tolower(substr($0, RSTART + 1, RLENGTH - 2))
}
# - basename?
basename=""
if (skip) {
basename = $1
} else {
if (match($0, /\|[_a-z0-9]+\(/)) {
basename = tolower(substr($0, RSTART + 1, RLENGTH - 2))
}
}
syscallname=""
if (skip) {
syscallname= syscallname "$"
}
if (length(compat) > 0) {
syscallname = syscallname "" compat "_"
}
if (length(alias) > 0) {
syscallname = syscallname "" alias
} else {
if (length(compatver) > 0) {
syscallname = syscallname "__" basename "" compatver
} else {
syscallname = syscallname "" basename
}
}
# Store the syscallname
syscalls[parsedsyscalls]=syscallname
# Extract syscall arguments
if (match($0, /\([^)]+\)/)) {
args = substr($0, RSTART + 1, RLENGTH - 2)
if (args == "void") {
syscallargs[parsedsyscalls] = "void"
syscallfullargs[parsedsyscalls] = "void"
} else {
# Normalize 'type * argument' to 'type *argument'
gsub("\\*[ \t]+", "*", args)
n = split(args, a, ",")
# Handle the first argument
match(a[1], /[*_a-z0-9\[\]]+$/)
syscallfullargs[parsedsyscalls] = substr(a[1], RSTART) "_"
gsub(".+[ *]", "", a[1])
syscallargs[parsedsyscalls] = a[1]
# Handle the rest of arguments
for (i = 2; i <= n; i++) {
match(a[i], /[*_a-zA-Z0-9\[\]]+$/)
fs = substr(a[i], RSTART)
if (fs ~ /\[/) {
sub(/\[/, "_[", fs)
} else {
fs = fs "_"
}
syscallfullargs[parsedsyscalls] = syscallfullargs[parsedsyscalls] "$" fs
gsub(".+[ *]", "", a[i])
syscallargs[parsedsyscalls] = syscallargs[parsedsyscalls] "$" a[i]
}
# Handle array arguments for syscall(2) and __syscall(2)
nargs = "arg0$arg1$arg2$arg3$arg4$arg5$arg6$arg7"
gsub(/args\[SYS_MAXSYSARGS\]/, nargs, syscallargs[parsedsyscalls])
}
}
parsedsyscalls++
# Done with this line
next
}
END {
# empty file?
if (NR < 1 && !abnormal_exit) {
usage()
}
# Handle abnormal exit
if (abnormal_exit) {
exit(abnormal_exit)
}
# Generate sanitizer_syscalls_netbsd.inc
# open pipe
cmd = clangformat " > " outputh
pcmd("//===-- netbsd_syscall_hooks.h --------------------------------------------===//")
pcmd("//")
pcmd("// The LLVM Compiler Infrastructure")
pcmd("//")
pcmd("// This file is distributed under the University of Illinois Open Source")
pcmd("// License. See LICENSE.TXT for details.")
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("//")
pcmd("// This file is a part of public sanitizer interface.")
pcmd("//")
pcmd("// System call handlers.")
pcmd("//")
pcmd("// Interface methods declared in this header implement pre- and post- syscall")
pcmd("// actions for the active sanitizer.")
pcmd("// Usage:")
pcmd("// __sanitizer_syscall_pre_getfoo(...args...);")
pcmd("// long long res = syscall(SYS_getfoo, ...args...);")
pcmd("// __sanitizer_syscall_post_getfoo(res, ...args...);")
pcmd("//")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("//")
pcmd("// Generated with: " script_name)
pcmd("// Generated date: " strftime("%F"))
pcmd("// Generated from: " syscallmasterversion)
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H")
pcmd("#define SANITIZER_NETBSD_SYSCALL_HOOKS_H")
pcmd("")
# TODO
pcmd("")
pcmd("#ifdef __cplusplus")
pcmd("extern \"C\" {")
pcmd("#endif")
pcmd("")
pcmd("// Private declarations. Do not call directly from user code. Use macros above.")
pcmd("")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("")
# TODO
pcmd("")
pcmd("#ifdef __cplusplus")
pcmd("} // extern \"C\"")
pcmd("#endif")
pcmd("")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("")
pcmd("#endif // SANITIZER_NETBSD_SYSCALL_HOOKS_H")
close(cmd)
# Generate sanitizer_syscalls_netbsd.inc
# open pipe
cmd = clangformat " > " outputinc
pcmd("//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===//")
pcmd("//")
pcmd("// The LLVM Compiler Infrastructure")
pcmd("//")
pcmd("// This file is distributed under the University of Illinois Open Source")
pcmd("// License. See LICENSE.TXT for details.")
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("//")
pcmd("// Common syscalls handlers for tools like AddressSanitizer,")
pcmd("// ThreadSanitizer, MemorySanitizer, etc.")
pcmd("//")
pcmd("// This file should be included into the tool's interceptor file,")
pcmd("// which has to define it's own macros:")
pcmd("// COMMON_SYSCALL_PRE_READ_RANGE")
pcmd("// Called in prehook for regions that will be read by the kernel and")
pcmd("// must be initialized.")
pcmd("// COMMON_SYSCALL_PRE_WRITE_RANGE")
pcmd("// Called in prehook for regions that will be written to by the kernel")
pcmd("// and must be addressable. The actual write range may be smaller than")
pcmd("// reported in the prehook. See POST_WRITE_RANGE.")
pcmd("// COMMON_SYSCALL_POST_READ_RANGE")
pcmd("// Called in posthook for regions that were read by the kernel. Does")
pcmd("// not make much sense.")
pcmd("// COMMON_SYSCALL_POST_WRITE_RANGE")
pcmd("// Called in posthook for regions that were written to by the kernel")
pcmd("// and are now initialized.")
pcmd("// COMMON_SYSCALL_ACQUIRE(addr)")
pcmd("// Acquire memory visibility from addr.")
pcmd("// COMMON_SYSCALL_RELEASE(addr)")
pcmd("// Release memory visibility to addr.")
pcmd("// COMMON_SYSCALL_FD_CLOSE(fd)")
pcmd("// Called before closing file descriptor fd.")
pcmd("// COMMON_SYSCALL_FD_ACQUIRE(fd)")
pcmd("// Acquire memory visibility from fd.")
pcmd("// COMMON_SYSCALL_FD_RELEASE(fd)")
pcmd("// Release memory visibility to fd.")
pcmd("// COMMON_SYSCALL_PRE_FORK()")
pcmd("// Called before fork syscall.")
pcmd("// COMMON_SYSCALL_POST_FORK(long long res)")
pcmd("// Called after fork syscall.")
pcmd("//")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("//")
pcmd("// Generated with: " script_name)
pcmd("// Generated date: " strftime("%F"))
pcmd("// Generated from: " syscallmasterversion)
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("")
pcmd("#include \"sanitizer_platform.h\"")
pcmd("#if SANITIZER_NETBSD")
pcmd("")
pcmd("#include \"sanitizer_libc.h\"")
pcmd("")
pcmd("#define PRE_SYSCALL(name) \\")
pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name")
pcmd("#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)")
pcmd("#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)")
pcmd("")
pcmd("#define POST_SYSCALL(name) \\")
pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name")
pcmd("#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)")
pcmd("#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_ACQUIRE")
pcmd("# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_RELEASE")
pcmd("# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_FD_CLOSE")
pcmd("# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_FD_ACQUIRE")
pcmd("# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_FD_RELEASE")
pcmd("# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_PRE_FORK")
pcmd("# define COMMON_SYSCALL_PRE_FORK() {}")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_POST_FORK")
pcmd("# define COMMON_SYSCALL_POST_FORK(res) {}")
pcmd("#endif")
pcmd("")
pcmd("// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).")
pcmd("")
pcmd("extern \"C\" {")
# TODO
pcmd("} // extern \"C\"")
pcmd("")
pcmd("#undef PRE_SYSCALL")
pcmd("#undef PRE_READ")
pcmd("#undef PRE_WRITE")
pcmd("#undef POST_SYSCALL")
pcmd("#undef POST_READ")
pcmd("#undef POST_WRITE")
pcmd("")
pcmd("#endif // SANITIZER_NETBSD")
close(cmd)
# Hack for preprocessed code
system("sed -i 's,^ \\([^ ]\\), \\1,' " outputinc)
}
function usage()
{
print "Usage: " script_name " syscalls.master"
abnormal_exit = 1
exit 1
}
function pcmd(string)
{
print string | cmd
}