]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/common/gennltvals.py
sim: nltvals: pull target syscalls out into a dedicated source file
[thirdparty/binutils-gdb.git] / sim / common / gennltvals.py
index cf23c3926994d20fa2d170dcc5506e8ad246f8bf..1e98691cb3d512ef7a88bbb73088b5bd55220452 100755 (executable)
@@ -37,49 +37,26 @@ from typing import Iterable, List, TextIO
 
 PROG = Path(__file__).name
 
-# Unfortunately, each newlib/libgloss port has seen fit to define their own
+# Unfortunately, many newlib/libgloss ports have seen fit to define their own
 # syscall.h file.  This means that system call numbers can vary for each port.
 # Support for all this crud is kept here, rather than trying to get too fancy.
 # If you want to try to improve this, please do, but don't break anything.
-# Note that there is a standard syscall.h file (libgloss/syscall.h) now which
-# hopefully more targets can use.
+#
+# If a target isn't listed here, it gets the standard syscall.h file (see
+# libgloss/syscall.h) which hopefully new targets will use.
 #
 # NB: New ports should use libgloss, not newlib.
 TARGET_DIRS = {
     'cr16': 'libgloss/cr16/sys',
     'd10v': 'newlib/libc/sys/d10v/sys',
-    'i960': 'libgloss/i960',
+    # Port removed from the tree years ago.
+    #'i960': 'libgloss/i960',
     'mcore': 'libgloss/mcore',
     'riscv': 'libgloss/riscv/machine',
     'sh': 'newlib/libc/sys/sh/sys',
     'v850': 'libgloss/v850/sys',
 }
-TARGETS = {
-    'bfin',
-    'cr16',
-    'd10v',
-    'fr30',
-    'frv',
-    'i960',
-    'iq2000',
-    'lm32',
-    'm32c',
-    'm32r',
-    'mcore',
-    'mn10200',
-    'mn10300',
-    'moxie',
-    'msp430',
-    'pru',
-    'riscv',
-    'rx',
-    'sh',
-    'sparc',
-    'v850',
-}
 
-# Make sure TARGET_DIRS doesn't gain any typos.
-assert not set(TARGET_DIRS) - TARGETS
 
 # The header for the generated def file.
 FILE_HEADER = f"""\
@@ -87,10 +64,46 @@ FILE_HEADER = f"""\
 /* This file is machine generated by {PROG}.  */\
 """
 
+# Used to update sections of files.
+START_MARKER = 'gennltvals: START'
+END_MARKER = 'gennltvals: END'
+
 
-def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
+def extract_syms(cpp: str, srcdir: Path,
+                 headers: Iterable[str],
+                 pattern: str,
+                 filter: str = r'^$') -> dict:
+    """Extract all the symbols from |headers| matching |pattern| using |cpp|."""
+    srcfile = ''.join(f'#include <{x}>\n' for x in headers)
+    syms = set()
+    define_pattern = re.compile(r'^#\s*define\s+(' + pattern + ')')
+    filter_pattern = re.compile(filter)
+    for header in headers:
+        with open(srcdir / header, 'r', encoding='utf-8') as fp:
+            data = fp.read()
+        for line in data.splitlines():
+            m = define_pattern.match(line)
+            if m and not filter_pattern.search(line):
+                syms.add(m.group(1))
+    for sym in syms:
+        srcfile += f'#ifdef {sym}\nDEFVAL "{sym}" {sym}\n#endif\n'
+
+    result = subprocess.run(
+        f'{cpp} -E -I"{srcdir}" -', shell=True, check=True, encoding='utf-8',
+        input=srcfile, capture_output=True)
+    ret = {}
+    for line in result.stdout.splitlines():
+        if line.startswith('DEFVAL '):
+            _, sym, val = line.split()
+            ret[sym.strip('"')] = val
+    return ret
+
+
+def gentvals(output_dir: Path, output: TextIO,
+             cpp: str, srctype: str, srcdir: Path,
              headers: Iterable[str],
              pattern: str,
+             filter: str = r'^$',
              target: str = None):
     """Extract constants from the specified files using a regular expression.
 
@@ -103,11 +116,32 @@ def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
         fullpath = srcdir / header
         assert fullpath.exists(), f'{fullpath} does not exist'
 
-    if target is None:
-        print(f'#ifdef {srctype}_defs', file=output)
-    else:
+    syms = extract_syms(cpp, srcdir, headers, pattern, filter)
+
+    # If we have a map file, use it directly.
+    target_map = output_dir / f'target-newlib-{srctype}.c'
+    if target_map.exists():
+        old_lines = target_map.read_text().splitlines()
+        start_i = end_i = None
+        for i, line in enumerate(old_lines):
+            if START_MARKER in line:
+                start_i = i
+            if END_MARKER in line:
+                end_i = i
+        assert start_i and end_i
+        new_lines = old_lines[0:start_i + 1]
+        new_lines.extend(
+            f'#ifdef {sym}\n'
+            f'  {{ "{sym}", {sym}, {val} }},\n'
+            f'#endif' for sym, val in sorted(syms.items()))
+        new_lines.extend(old_lines[end_i:])
+        target_map.write_text('\n'.join(new_lines) + '\n')
+        return
+
+    # Fallback to classic nltvals.def.
+    if target is not None:
         print(f'#ifdef NL_TARGET_{target}', file=output)
-        print(f'#ifdef {srctype}_defs', file=output)
+    print(f'#ifdef {srctype}_defs', file=output)
 
     print('\n'.join(f'/* from {x} */' for x in headers), file=output)
 
@@ -116,64 +150,114 @@ def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
     else:
         print(f'/* begin {target} {srctype} target macros */', file=output)
 
-    # Extract all the symbols.
-    srcfile = ''.join(f'#include <{x}>\n' for x in headers)
-    syms = set()
-    define_pattern = re.compile(r'^#\s*define\s+(' + pattern + ')')
-    for header in headers:
-        with open(srcdir / header, 'r', encoding='utf-8') as fp:
-            data = fp.read()
-        for line in data.splitlines():
-            m = define_pattern.match(line)
-            if m:
-                syms.add(m.group(1))
-    for sym in sorted(syms):
-        srcfile += f'#ifdef {sym}\nDEFVAL {{ "{sym}", {sym} }},\n#endif\n'
-
-    result = subprocess.run(
-        f'{cpp} -E -I"{srcdir}" -', shell=True, check=True, encoding='utf-8',
-        input=srcfile, capture_output=True)
-    for line in result.stdout.splitlines():
-        if line.startswith('DEFVAL '):
-            print(line[6:].rstrip(), file=output)
+    for sym, val in sorted(syms.items()):
+        print(f' {{ "{sym}", {val} }},', file=output)
 
+    print(f'#undef {srctype}_defs', file=output)
     if target is None:
         print(f'/* end {srctype} target macros */', file=output)
-        print('#endif', file=output)
     else:
         print(f'/* end {target} {srctype} target macros */', file=output)
         print('#endif', file=output)
-        print('#endif', file=output)
+    print('#endif', file=output)
 
 
-def gen_common(output: TextIO, newlib: Path, cpp: str):
+def gen_common(output_dir: Path, output: TextIO, newlib: Path, cpp: str):
     """Generate the common C library constants.
 
     No arch should override these.
     """
-    gentvals(output, cpp, 'errno', newlib / 'newlib/libc/include',
+    gentvals(output_dir, output, cpp, 'errno', newlib / 'newlib/libc/include',
              ('errno.h', 'sys/errno.h'), 'E[A-Z0-9]*')
 
-    gentvals(output, cpp, 'signal', newlib / 'newlib/libc/include',
-             ('signal.h', 'sys/signal.h'), r'SIG[A-Z0-9]*')
+    gentvals(output_dir, output, cpp, 'signal', newlib / 'newlib/libc/include',
+             ('signal.h', 'sys/signal.h'), r'SIG[A-Z0-9]*', filter=r'SIGSTKSZ')
 
-    gentvals(output, cpp, 'open', newlib / 'newlib/libc/include',
+    gentvals(output_dir, output, cpp, 'open', newlib / 'newlib/libc/include',
              ('fcntl.h', 'sys/fcntl.h', 'sys/_default_fcntl.h'), r'O_[A-Z0-9]*')
 
 
-def gen_targets(output: TextIO, newlib: Path, cpp: str):
+def gen_target_syscall(output_dir: Path, newlib: Path, cpp: str):
+    """Generate the target-specific syscall lists."""
+    target_map_c = output_dir / 'target-newlib-syscall.c'
+    old_lines_c = target_map_c.read_text().splitlines()
+    start_i = end_i = None
+    for i, line in enumerate(old_lines_c):
+        if START_MARKER in line:
+            start_i = i
+        if END_MARKER in line:
+            end_i = i
+    assert start_i and end_i, f'{target_map_c}: Unable to find markers'
+    new_lines_c = old_lines_c[0:start_i + 1]
+    new_lines_c_end = old_lines_c[end_i:]
+
+    target_map_h = output_dir / 'target-newlib-syscall.h'
+    old_lines_h = target_map_h.read_text().splitlines()
+    start_i = end_i = None
+    for i, line in enumerate(old_lines_h):
+        if START_MARKER in line:
+            start_i = i
+        if END_MARKER in line:
+            end_i = i
+    assert start_i and end_i, f'{target_map_h}: Unable to find markers'
+    new_lines_h = old_lines_h[0:start_i + 1]
+    new_lines_h_end = old_lines_h[end_i:]
+
+    headers = ('syscall.h',)
+    pattern = r'SYS_[_a-zA-Z0-9]*'
+
+    # Output the target-specific syscalls.
+    for target, subdir in sorted(TARGET_DIRS.items()):
+        syms = extract_syms(cpp, newlib / subdir, headers, pattern)
+        new_lines_c.append(f'CB_TARGET_DEFS_MAP cb_{target}_syscall_map[] = {{')
+        new_lines_c.extend(
+            f'#ifdef CB_{sym}\n'
+            '  { '
+            f'"{sym[4:]}", CB_{sym}, TARGET_NEWLIB_{target.upper()}_{sym}'
+            ' },\n'
+            '#endif' for sym in sorted(syms))
+        new_lines_c.append('  {NULL, -1, -1},')
+        new_lines_c.append('};\n')
+
+        new_lines_h.append(
+            f'extern CB_TARGET_DEFS_MAP cb_{target}_syscall_map[];')
+        new_lines_h.extend(
+            f'#define TARGET_NEWLIB_{target.upper()}_{sym} {val}'
+            for sym, val in sorted(syms.items()))
+        new_lines_h.append('')
+
+    # Then output the common syscall targets.
+    syms = extract_syms(cpp, newlib / 'libgloss', headers, pattern)
+    new_lines_c.append(f'CB_TARGET_DEFS_MAP cb_init_syscall_map[] = {{')
+    new_lines_c.extend(
+        f'#ifdef CB_{sym}\n'
+        f'  {{ "{sym[4:]}", CB_{sym}, TARGET_NEWLIB_{sym} }},\n'
+        f'#endif' for sym in sorted(syms))
+    new_lines_c.append('  {NULL, -1, -1},')
+    new_lines_c.append('};')
+
+    new_lines_h.append('extern CB_TARGET_DEFS_MAP cb_init_syscall_map[];')
+    new_lines_h.extend(
+        f'#define TARGET_NEWLIB_{sym} {val}'
+        for sym, val in sorted(syms.items()))
+
+    new_lines_c.extend(new_lines_c_end)
+    target_map_c.write_text('\n'.join(new_lines_c) + '\n')
+
+    new_lines_h.extend(new_lines_h_end)
+    target_map_h.write_text('\n'.join(new_lines_h) + '\n')
+
+
+def gen_targets(output_dir: Path, output: TextIO, newlib: Path, cpp: str):
     """Generate the target-specific lists."""
-    for target in sorted(TARGETS):
-        subdir = TARGET_DIRS.get(target, 'libgloss')
-        gentvals(output, cpp, 'sys', newlib / subdir, ('syscall.h',),
-                 r'SYS_[_a-zA-Z0-9]*', target=target)
+    gen_target_syscall(output_dir, newlib, cpp)
 
 
-def gen(output: TextIO, newlib: Path, cpp: str):
+def gen(output_dir: Path, output: TextIO, newlib: Path, cpp: str):
     """Generate all the things!"""
     print(FILE_HEADER, file=output)
-    gen_common(output, newlib, cpp)
-    gen_targets(output, newlib, cpp)
+    gen_common(output_dir, output, newlib, cpp)
+    gen_targets(output_dir, output, newlib, cpp)
 
 
 def get_parser() -> argparse.ArgumentParser:
@@ -183,7 +267,7 @@ def get_parser() -> argparse.ArgumentParser:
         formatter_class=argparse.RawDescriptionHelpFormatter)
     parser.add_argument(
         '-o', '--output', type=Path,
-        help='write to the specified file instead of stdout')
+        help='write to the specified directory')
     parser.add_argument(
         '--cpp', type=str, default='cpp',
         help='the preprocessor to use')
@@ -201,8 +285,14 @@ def parse_args(argv: List[str]) -> argparse.Namespace:
     parser = get_parser()
     opts = parser.parse_args(argv)
 
+    if opts.output is None:
+        # Default to where the script lives.
+        opts.output = Path(__file__).resolve().parent
+
     if opts.srcroot is None:
         opts.srcroot = Path(__file__).resolve().parent.parent.parent
+    else:
+        opts.srcroot = opts.srcroot.resolve()
 
     if opts.newlib is None:
         # Try to find newlib relative to our source tree.
@@ -225,12 +315,9 @@ def main(argv: List[str]) -> int:
     """The main entry point for scripts."""
     opts = parse_args(argv)
 
-    if opts.output is not None:
-        output = open(opts.output, 'w', encoding='utf-8')
-    else:
-        output = sys.stdout
+    output = (opts.output / 'nltvals.def').open('w', encoding='utf-8')
 
-    gen(output, opts.newlib, opts.cpp)
+    gen(opts.output, output, opts.newlib, opts.cpp)
     return 0