genfunctosyscallnrs: maps bionic functions to syscall numbers.

Bionic maps typical C functions like setresuid() to a syscall,
depending on the architecture used. This tool generates a .h
file that maps all bionic functions in SYSCALLS.txt to the
syscall number used on a particular architecture. It can then
be used to generate correct seccomp policy at runtime.

Example output in func_to_syscall_nrs.h:

Bug: 111434506
Test: manually inspect func_to_syscall_nrs.h
Change-Id: I8bc5c1cb17a2e7b5c534b2e0496411f2d419ad86
diff --git a/libc/Android.bp b/libc/Android.bp
index e0d0fee..ddc2805 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -2165,6 +2165,52 @@
     },
 }
 
+python_binary_host {
+    name: "genfunctosyscallnrs",
+    main: "tools/genfunctosyscallnrs.py",
+
+    srcs: [
+        "tools/genseccomp.py",
+        "tools/genfunctosyscallnrs.py",
+        "tools/gensyscalls.py",
+    ],
+
+    data: [
+        "kernel/uapi/**/*.h",
+    ],
+
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+cc_genrule {
+    name: "func_to_syscall_nrs",
+    recovery_available: true,
+    cmd: "$(location genfunctosyscallnrs) --out-dir=$(genDir) $(in)",
+
+    tools: [ "genfunctosyscallnrs" ],
+
+    srcs: [
+        "SYSCALLS.TXT",
+        ":libseccomp_gen_syscall_nrs_arm",
+        ":libseccomp_gen_syscall_nrs_arm64",
+        ":libseccomp_gen_syscall_nrs_mips",
+        ":libseccomp_gen_syscall_nrs_mips64",
+        ":libseccomp_gen_syscall_nrs_x86",
+        ":libseccomp_gen_syscall_nrs_x86_64",
+    ],
+
+    out: [
+        "func_to_syscall_nrs.h",
+    ],
+}
+
 cc_genrule {
     name: "libseccomp_policy_app_sources",
     recovery_available: true,
diff --git a/libc/seccomp/seccomp_policy.cpp b/libc/seccomp/seccomp_policy.cpp
index 3d617be..75871c0 100644
--- a/libc/seccomp/seccomp_policy.cpp
+++ b/libc/seccomp/seccomp_policy.cpp
@@ -27,7 +27,6 @@
 
 #include "seccomp_bpfs.h"
 
-
 #if defined __arm__ || defined __aarch64__
 
 #define DUAL_ARCH
diff --git a/libc/tools/genfunctosyscallnrs.py b/libc/tools/genfunctosyscallnrs.py
new file mode 100755
index 0000000..6a456f2
--- /dev/null
+++ b/libc/tools/genfunctosyscallnrs.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+import argparse
+import collections
+import logging
+import os
+import re
+import subprocess
+import textwrap
+
+from gensyscalls import SysCallsTxtParser
+from genseccomp import parse_syscall_NRs
+
+def load_syscall_names_from_file(file_path, architecture):
+  parser = SysCallsTxtParser()
+  parser.parse_open_file(open(file_path))
+  arch_map = {}
+  for syscall in parser.syscalls:
+    if syscall.get(architecture):
+      arch_map[syscall["func"]] = syscall["name"];
+
+  return arch_map
+
+def gen_syscall_nrs(out_file, base_syscall_file, syscall_NRs):
+  for arch in ('arm', 'arm64', 'mips', 'mips64', 'x86', 'x86_64'):
+    base_names = load_syscall_names_from_file(base_syscall_file, arch)
+
+    for func,syscall in base_names.iteritems():
+      out_file.write("#define __" + arch + "_" + func + " " + str(syscall_NRs[arch][syscall]) + ";\n")
+
+def main():
+  parser = argparse.ArgumentParser(
+      description="Generates a mapping of bionic functions to system call numbers per architecture.")
+  parser.add_argument("--verbose", "-v", help="Enables verbose logging.")
+  parser.add_argument("--out-dir",
+                      help="The output directory for the output files")
+  parser.add_argument("base_file", metavar="base-file", type=str,
+                      help="The path of the base syscall list (SYSCALLS.TXT).")
+  parser.add_argument("files", metavar="FILE", type=str, nargs="+",
+                      help=("A syscall name-number mapping file for an architecture.\n"))
+  args = parser.parse_args()
+
+  if args.verbose:
+    logging.basicConfig(level=logging.DEBUG)
+  else:
+    logging.basicConfig(level=logging.INFO)
+
+  syscall_files = []
+  syscall_NRs = {}
+  for filename in args.files:
+    m = re.search(r"libseccomp_gen_syscall_nrs_([^/]+)", filename)
+    syscall_NRs[m.group(1)] = parse_syscall_NRs(filename)
+
+  output_path = os.path.join(args.out_dir, "func_to_syscall_nrs.h")
+  with open(output_path, "w") as output_file:
+    gen_syscall_nrs(out_file=output_file,
+             syscall_NRs=syscall_NRs, base_syscall_file=args.base_file)
+
+if __name__ == "__main__":
+  main()