Kamil Rytarowski | 39628a7 | 2018-02-15 02:43:02 +0000 | [diff] [blame] | 1 | #!/usr/bin/awk -f |
| 2 | |
| 3 | #===-- generate_netbsd_syscalls.awk ----------------------------------------===# |
| 4 | # |
| 5 | # The LLVM Compiler Infrastructure |
| 6 | # |
| 7 | # This file is distributed under the University of Illinois Open Source |
| 8 | # License. See LICENSE.TXT for details. |
| 9 | # |
| 10 | #===------------------------------------------------------------------------===# |
| 11 | # |
| 12 | # This file is a generator of: |
| 13 | # - include/sanitizer/netbsd_syscall_hooks.h |
| 14 | # - lib/sanitizer_common/sanitizer_syscalls_netbsd.inc |
| 15 | # |
| 16 | # This script accepts on the input syscalls.master by default located in the |
| 17 | # /usr/src/sys/kern/syscalls.master path in the NetBSD distribution. |
| 18 | # |
| 19 | # NetBSD version 8.0. |
| 20 | # |
| 21 | #===------------------------------------------------------------------------===# |
| 22 | |
| 23 | BEGIN { |
| 24 | # harcode the script name |
| 25 | script_name = "generate_netbsd_syscalls.awk" |
| 26 | outputh = "../include/sanitizer/netbsd_syscall_hooks.h" |
| 27 | outputinc = "../lib/sanitizer_common/sanitizer_syscalls_netbsd.inc" |
| 28 | |
| 29 | # assert that we are in the directory with scripts |
| 30 | in_utils = system("test -f " script_name " && exit 1 || exit 0") |
| 31 | if (in_utils == 0) { |
| 32 | usage() |
| 33 | } |
| 34 | |
| 35 | # assert 1 argument passed |
| 36 | if (ARGC != 2) { |
| 37 | usage() |
| 38 | } |
| 39 | |
| 40 | # assert argument is a valid file path to syscall.master |
| 41 | if (system("test -f " ARGV[1]) != 0) { |
| 42 | usage() |
| 43 | } |
| 44 | |
| 45 | # sanity check that the path ends with "syscall.master" |
| 46 | if (ARGV[1] !~ /syscalls\.master$/) { |
| 47 | usage() |
| 48 | } |
| 49 | |
| 50 | # accept overloading CLANGFORMAT from environment |
| 51 | clangformat = "clang-format" |
| 52 | if ("CLANGFORMAT" in ENVIRON) { |
| 53 | clangformat = ENVIRON["CLANGFORMAT"] |
| 54 | } |
| 55 | |
| 56 | # parsing specific symbols |
| 57 | parsingheader=1 |
| 58 | |
| 59 | parsedsyscalls=0 |
| 60 | |
| 61 | # Hardcoded in algorithm |
| 62 | SYS_MAXSYSARGS=8 |
| 63 | } |
| 64 | |
| 65 | # Parse the RCS ID from syscall.master |
| 66 | parsingheader == 1 && NR == 1 { |
| 67 | if (match($0, /\$[^$]+\$/)) { |
| 68 | # trim initial 'NetBSD: ' and trailing ' $' |
| 69 | syscallmasterversion = substr($0, RSTART + 9, RLENGTH - 11) |
| 70 | } else { |
| 71 | # wrong file? |
| 72 | usage() |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | # skip the following lines |
| 77 | # - empty |
| 78 | NF == 0 { |
| 79 | next |
| 80 | } |
| 81 | # - comment |
| 82 | $1 == ";" { |
| 83 | next |
| 84 | } |
| 85 | |
| 86 | # separator between the header and table with syscalls |
| 87 | $0 == "%%" { |
| 88 | parsingheader = 0 |
| 89 | next |
| 90 | } |
| 91 | |
| 92 | # preserve 'if/elif/else/endif' C preprocessor as-is |
| 93 | parsingheader == 0 && $0 ~ /^#/ { |
| 94 | if (parsedsyscalls in ifelifelseendif) { |
| 95 | ifelifelseendif[parsedsyscalls] = ifelifelseendif[parsedsyscalls] "\n" $0 |
| 96 | } else { |
| 97 | ifelifelseendif[parsedsyscalls] = $0 |
| 98 | } |
| 99 | next |
| 100 | } |
| 101 | |
| 102 | # parsing of syscall definitions |
| 103 | parsingheader == 0 && $1 ~ /^[0-9]+$/ { |
| 104 | # first join multiple lines into single one |
| 105 | while (sub(/\\$/, "")) { |
| 106 | getline line |
| 107 | $0 = $0 "" line |
| 108 | } |
| 109 | |
| 110 | # Skip unwanted syscalls |
| 111 | skip=0 |
| 112 | if ($0 ~ /OBSOL/ || $0 ~ /EXCL/ || $0 ~ /UNIMPL/) { |
| 113 | skip=1 |
| 114 | } |
| 115 | |
| 116 | # Compose the syscall name |
| 117 | # - compat? |
| 118 | compat="" |
| 119 | if (match($0, /COMPAT_[0-9]+/)) { |
| 120 | compat = tolower(substr($0, RSTART, RLENGTH)) |
| 121 | } |
| 122 | # - alias name? |
| 123 | alias="" |
| 124 | if ($(NF) != "}" && !skip) { |
| 125 | alias = alias "" $(NF) |
| 126 | } |
| 127 | # - compat version? |
| 128 | compatver="" |
| 129 | if (match($0, /\|[0-9]+\|/)) { |
| 130 | compatver = tolower(substr($0, RSTART + 1, RLENGTH - 2)) |
| 131 | } |
| 132 | # - basename? |
| 133 | basename="" |
| 134 | if (skip) { |
| 135 | basename = $1 |
| 136 | } else { |
| 137 | if (match($0, /\|[_a-z0-9]+\(/)) { |
| 138 | basename = tolower(substr($0, RSTART + 1, RLENGTH - 2)) |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | syscallname="" |
| 143 | |
| 144 | if (skip) { |
| 145 | syscallname= syscallname "$" |
| 146 | } |
| 147 | |
| 148 | if (length(compat) > 0) { |
| 149 | syscallname = syscallname "" compat "_" |
| 150 | } |
| 151 | if (length(alias) > 0) { |
| 152 | syscallname = syscallname "" alias |
| 153 | } else { |
| 154 | if (length(compatver) > 0) { |
| 155 | syscallname = syscallname "__" basename "" compatver |
| 156 | } else { |
| 157 | syscallname = syscallname "" basename |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | # Store the syscallname |
| 162 | syscalls[parsedsyscalls]=syscallname |
| 163 | |
| 164 | # Extract syscall arguments |
| 165 | if (match($0, /\([^)]+\)/)) { |
| 166 | args = substr($0, RSTART + 1, RLENGTH - 2) |
| 167 | |
| 168 | if (args == "void") { |
| 169 | syscallargs[parsedsyscalls] = "void" |
| 170 | syscallfullargs[parsedsyscalls] = "void" |
| 171 | } else { |
| 172 | # Normalize 'type * argument' to 'type *argument' |
| 173 | gsub("\\*[ \t]+", "*", args) |
| 174 | |
| 175 | n = split(args, a, ",") |
| 176 | |
| 177 | # Handle the first argument |
| 178 | match(a[1], /[*_a-z0-9\[\]]+$/) |
| 179 | syscallfullargs[parsedsyscalls] = substr(a[1], RSTART) "_" |
| 180 | |
| 181 | gsub(".+[ *]", "", a[1]) |
| 182 | syscallargs[parsedsyscalls] = a[1] |
| 183 | |
| 184 | # Handle the rest of arguments |
| 185 | for (i = 2; i <= n; i++) { |
| 186 | match(a[i], /[*_a-zA-Z0-9\[\]]+$/) |
| 187 | fs = substr(a[i], RSTART) |
| 188 | if (fs ~ /\[/) { |
| 189 | sub(/\[/, "_[", fs) |
| 190 | } else { |
| 191 | fs = fs "_" |
| 192 | } |
| 193 | syscallfullargs[parsedsyscalls] = syscallfullargs[parsedsyscalls] "$" fs |
| 194 | gsub(".+[ *]", "", a[i]) |
| 195 | syscallargs[parsedsyscalls] = syscallargs[parsedsyscalls] "$" a[i] |
| 196 | } |
| 197 | |
| 198 | # Handle array arguments for syscall(2) and __syscall(2) |
| 199 | nargs = "arg0$arg1$arg2$arg3$arg4$arg5$arg6$arg7" |
| 200 | gsub(/args\[SYS_MAXSYSARGS\]/, nargs, syscallargs[parsedsyscalls]) |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | parsedsyscalls++ |
| 205 | |
| 206 | # Done with this line |
| 207 | next |
| 208 | } |
| 209 | |
| 210 | |
| 211 | END { |
| 212 | # empty file? |
| 213 | if (NR < 1 && !abnormal_exit) { |
| 214 | usage() |
| 215 | } |
| 216 | |
| 217 | # Handle abnormal exit |
| 218 | if (abnormal_exit) { |
| 219 | exit(abnormal_exit) |
| 220 | } |
| 221 | |
| 222 | # Generate sanitizer_syscalls_netbsd.inc |
| 223 | |
| 224 | # open pipe |
| 225 | cmd = clangformat " > " outputh |
| 226 | |
| 227 | pcmd("//===-- netbsd_syscall_hooks.h --------------------------------------------===//") |
| 228 | pcmd("//") |
| 229 | pcmd("// The LLVM Compiler Infrastructure") |
| 230 | pcmd("//") |
| 231 | pcmd("// This file is distributed under the University of Illinois Open Source") |
| 232 | pcmd("// License. See LICENSE.TXT for details.") |
| 233 | pcmd("//") |
| 234 | pcmd("//===----------------------------------------------------------------------===//") |
| 235 | pcmd("//") |
| 236 | pcmd("// This file is a part of public sanitizer interface.") |
| 237 | pcmd("//") |
| 238 | pcmd("// System call handlers.") |
| 239 | pcmd("//") |
| 240 | pcmd("// Interface methods declared in this header implement pre- and post- syscall") |
| 241 | pcmd("// actions for the active sanitizer.") |
| 242 | pcmd("// Usage:") |
| 243 | pcmd("// __sanitizer_syscall_pre_getfoo(...args...);") |
| 244 | pcmd("// long long res = syscall(SYS_getfoo, ...args...);") |
| 245 | pcmd("// __sanitizer_syscall_post_getfoo(res, ...args...);") |
| 246 | pcmd("//") |
| 247 | pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") |
| 248 | pcmd("//") |
| 249 | pcmd("// Generated with: " script_name) |
| 250 | pcmd("// Generated date: " strftime("%F")) |
| 251 | pcmd("// Generated from: " syscallmasterversion) |
| 252 | pcmd("//") |
| 253 | pcmd("//===----------------------------------------------------------------------===//") |
| 254 | pcmd("#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H") |
| 255 | pcmd("#define SANITIZER_NETBSD_SYSCALL_HOOKS_H") |
| 256 | pcmd("") |
| 257 | |
| 258 | # TODO |
| 259 | |
| 260 | pcmd("") |
| 261 | pcmd("#ifdef __cplusplus") |
| 262 | pcmd("extern \"C\" {") |
| 263 | pcmd("#endif") |
| 264 | pcmd("") |
| 265 | pcmd("// Private declarations. Do not call directly from user code. Use macros above.") |
| 266 | pcmd("") |
| 267 | pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") |
| 268 | pcmd("") |
| 269 | |
| 270 | # TODO |
| 271 | |
| 272 | pcmd("") |
| 273 | pcmd("#ifdef __cplusplus") |
| 274 | pcmd("} // extern \"C\"") |
| 275 | pcmd("#endif") |
| 276 | |
| 277 | pcmd("") |
| 278 | pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") |
| 279 | pcmd("") |
| 280 | |
| 281 | pcmd("#endif // SANITIZER_NETBSD_SYSCALL_HOOKS_H") |
| 282 | |
| 283 | close(cmd) |
| 284 | |
| 285 | # Generate sanitizer_syscalls_netbsd.inc |
| 286 | |
| 287 | # open pipe |
| 288 | cmd = clangformat " > " outputinc |
| 289 | |
| 290 | pcmd("//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===//") |
| 291 | pcmd("//") |
| 292 | pcmd("// The LLVM Compiler Infrastructure") |
| 293 | pcmd("//") |
| 294 | pcmd("// This file is distributed under the University of Illinois Open Source") |
| 295 | pcmd("// License. See LICENSE.TXT for details.") |
| 296 | pcmd("//") |
| 297 | pcmd("//===----------------------------------------------------------------------===//") |
| 298 | pcmd("//") |
| 299 | pcmd("// Common syscalls handlers for tools like AddressSanitizer,") |
| 300 | pcmd("// ThreadSanitizer, MemorySanitizer, etc.") |
| 301 | pcmd("//") |
| 302 | pcmd("// This file should be included into the tool's interceptor file,") |
| 303 | pcmd("// which has to define it's own macros:") |
| 304 | pcmd("// COMMON_SYSCALL_PRE_READ_RANGE") |
| 305 | pcmd("// Called in prehook for regions that will be read by the kernel and") |
| 306 | pcmd("// must be initialized.") |
| 307 | pcmd("// COMMON_SYSCALL_PRE_WRITE_RANGE") |
| 308 | pcmd("// Called in prehook for regions that will be written to by the kernel") |
| 309 | pcmd("// and must be addressable. The actual write range may be smaller than") |
| 310 | pcmd("// reported in the prehook. See POST_WRITE_RANGE.") |
| 311 | pcmd("// COMMON_SYSCALL_POST_READ_RANGE") |
| 312 | pcmd("// Called in posthook for regions that were read by the kernel. Does") |
| 313 | pcmd("// not make much sense.") |
| 314 | pcmd("// COMMON_SYSCALL_POST_WRITE_RANGE") |
| 315 | pcmd("// Called in posthook for regions that were written to by the kernel") |
| 316 | pcmd("// and are now initialized.") |
| 317 | pcmd("// COMMON_SYSCALL_ACQUIRE(addr)") |
| 318 | pcmd("// Acquire memory visibility from addr.") |
| 319 | pcmd("// COMMON_SYSCALL_RELEASE(addr)") |
| 320 | pcmd("// Release memory visibility to addr.") |
| 321 | pcmd("// COMMON_SYSCALL_FD_CLOSE(fd)") |
| 322 | pcmd("// Called before closing file descriptor fd.") |
| 323 | pcmd("// COMMON_SYSCALL_FD_ACQUIRE(fd)") |
| 324 | pcmd("// Acquire memory visibility from fd.") |
| 325 | pcmd("// COMMON_SYSCALL_FD_RELEASE(fd)") |
| 326 | pcmd("// Release memory visibility to fd.") |
| 327 | pcmd("// COMMON_SYSCALL_PRE_FORK()") |
| 328 | pcmd("// Called before fork syscall.") |
| 329 | pcmd("// COMMON_SYSCALL_POST_FORK(long long res)") |
| 330 | pcmd("// Called after fork syscall.") |
| 331 | pcmd("//") |
| 332 | pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") |
| 333 | pcmd("//") |
| 334 | pcmd("// Generated with: " script_name) |
| 335 | pcmd("// Generated date: " strftime("%F")) |
| 336 | pcmd("// Generated from: " syscallmasterversion) |
| 337 | pcmd("//") |
| 338 | pcmd("//===----------------------------------------------------------------------===//") |
| 339 | pcmd("") |
| 340 | pcmd("#include \"sanitizer_platform.h\"") |
| 341 | pcmd("#if SANITIZER_NETBSD") |
| 342 | pcmd("") |
| 343 | pcmd("#include \"sanitizer_libc.h\"") |
| 344 | pcmd("") |
| 345 | pcmd("#define PRE_SYSCALL(name) \\") |
| 346 | pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name") |
| 347 | pcmd("#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)") |
| 348 | pcmd("#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)") |
| 349 | pcmd("") |
| 350 | pcmd("#define POST_SYSCALL(name) \\") |
| 351 | pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name") |
| 352 | pcmd("#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)") |
| 353 | pcmd("#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)") |
| 354 | pcmd("") |
| 355 | pcmd("#ifndef COMMON_SYSCALL_ACQUIRE") |
| 356 | pcmd("# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))") |
| 357 | pcmd("#endif") |
| 358 | pcmd("") |
| 359 | pcmd("#ifndef COMMON_SYSCALL_RELEASE") |
| 360 | pcmd("# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))") |
| 361 | pcmd("#endif") |
| 362 | pcmd("") |
| 363 | pcmd("#ifndef COMMON_SYSCALL_FD_CLOSE") |
| 364 | pcmd("# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))") |
| 365 | pcmd("#endif") |
| 366 | pcmd("") |
| 367 | pcmd("#ifndef COMMON_SYSCALL_FD_ACQUIRE") |
| 368 | pcmd("# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))") |
| 369 | pcmd("#endif") |
| 370 | pcmd("") |
| 371 | pcmd("#ifndef COMMON_SYSCALL_FD_RELEASE") |
| 372 | pcmd("# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))") |
| 373 | pcmd("#endif") |
| 374 | pcmd("") |
| 375 | pcmd("#ifndef COMMON_SYSCALL_PRE_FORK") |
| 376 | pcmd("# define COMMON_SYSCALL_PRE_FORK() {}") |
| 377 | pcmd("#endif") |
| 378 | pcmd("") |
| 379 | pcmd("#ifndef COMMON_SYSCALL_POST_FORK") |
| 380 | pcmd("# define COMMON_SYSCALL_POST_FORK(res) {}") |
| 381 | pcmd("#endif") |
| 382 | pcmd("") |
| 383 | pcmd("// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).") |
| 384 | pcmd("") |
| 385 | pcmd("extern \"C\" {") |
| 386 | |
| 387 | # TODO |
| 388 | |
| 389 | pcmd("} // extern \"C\"") |
| 390 | pcmd("") |
| 391 | pcmd("#undef PRE_SYSCALL") |
| 392 | pcmd("#undef PRE_READ") |
| 393 | pcmd("#undef PRE_WRITE") |
| 394 | pcmd("#undef POST_SYSCALL") |
| 395 | pcmd("#undef POST_READ") |
| 396 | pcmd("#undef POST_WRITE") |
| 397 | pcmd("") |
| 398 | pcmd("#endif // SANITIZER_NETBSD") |
| 399 | |
| 400 | close(cmd) |
| 401 | |
| 402 | # Hack for preprocessed code |
| 403 | system("sed -i 's,^ \\([^ ]\\), \\1,' " outputinc) |
| 404 | } |
| 405 | |
| 406 | function usage() |
| 407 | { |
| 408 | print "Usage: " script_name " syscalls.master" |
| 409 | abnormal_exit = 1 |
| 410 | exit 1 |
| 411 | } |
| 412 | |
| 413 | function pcmd(string) |
| 414 | { |
| 415 | print string | cmd |
| 416 | } |