sim: syscall: fix argvlen & argv implementation
[binutils-gdb.git] / sim / common / gennltvals.py
index b3e558d580a91c56c1bd2a3791b9152ea78afd82..3006f7f58fe4743aa503c4b3802449c29382e249 100755 (executable)
@@ -63,10 +63,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.
 
@@ -79,6 +115,29 @@ def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
         fullpath = srcdir / header
         assert fullpath.exists(), f'{fullpath} does not exist'
 
+    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)
@@ -90,26 +149,8 @@ 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:
@@ -120,37 +161,37 @@ def gentvals(output: TextIO, cpp: str, srctype: str, srcdir: Path,
     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_targets(output_dir: Path, output: TextIO, newlib: Path, cpp: str):
     """Generate the target-specific lists."""
     for target, subdir in sorted(TARGET_DIRS.items()):
-        gentvals(output, cpp, 'sys', newlib / subdir, ('syscall.h',),
-                 r'SYS_[_a-zA-Z0-9]*', target=target)
+        gentvals(output_dir, output, cpp, 'sys', newlib / subdir,
+                 ('syscall.h',), r'SYS_[_a-zA-Z0-9]*', target=target)
 
     # Then output the common syscall targets.
-    gentvals(output, cpp, 'sys', newlib / 'libgloss', ('syscall.h',),
-             r'SYS_[_a-zA-Z0-9]*')
+    gentvals(output_dir, output, cpp, 'sys', newlib / 'libgloss',
+             ('syscall.h',), r'SYS_[_a-zA-Z0-9]*')
 
 
-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:
@@ -160,7 +201,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')
@@ -178,8 +219,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.
@@ -202,12 +249,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