mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Luis Augenstein <luis.augenstein@tngtech.com>
To: nathan@kernel.org, nsc@kernel.org
Cc: linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org,
	akpm@linux-foundation.org, gregkh@linuxfoundation.org,
	kstewart@linuxfoundation.org, maximilian.huber@tngtech.com,
	Luis Augenstein <luis.augenstein@tngtech.com>
Subject: [PATCH v3 7/7] scripts/sbom: remove the command-specific parsers
Date: Mon, 12 Oct 2026 23:33:22 +0200	[thread overview]
Message-ID: <20261012213337.2466524-8-luis.augenstein@tngtech.com> (raw)
In-Reply-To: <20261012213337.2466524-1-luis.augenstein@tngtech.com>

With the build inputs taken from make_prereqs_ and deps_, the
command-specific parsers are no longer needed. Remove them, and with
them the --do-not-fail-on-unknown-build-command option, which only
existed to tolerate build commands that the parsers did not support.

Assisted-by: LLM
Co-developed-by: Maximilian Huber <maximilian.huber@tngtech.com>
Signed-off-by: Maximilian Huber <maximilian.huber@tngtech.com>
Signed-off-by: Luis Augenstein <luis.augenstein@tngtech.com>
---
 Documentation/tools/sbom/sbom.rst             |  22 +-
 scripts/sbom/sbom/cmd_graph/cmd_file.py       |   5 +-
 scripts/sbom/sbom/cmd_graph/cmd_graph_node.py |   5 +-
 .../sbom/cmd_graph/hardcoded_dependencies.py  |   1 -
 .../cmd_graph/savedcmd_parser/__init__.py     |   6 -
 .../command_parser_registry.py                | 516 ------------------
 .../savedcmd_parser/command_splitter.py       | 128 -----
 .../savedcmd_parser/savedcmd_parser.py        |  67 ---
 .../cmd_graph/savedcmd_parser/tokenizer.py    |  92 ----
 scripts/sbom/sbom/config.py                   |  14 -
 .../tests/cmd_graph/test_savedcmd_parser.py   | 468 ----------------
 11 files changed, 5 insertions(+), 1319 deletions(-)
 delete mode 100644 scripts/sbom/sbom/cmd_graph/savedcmd_parser/__init__.py
 delete mode 100644 scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_parser_registry.py
 delete mode 100644 scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_splitter.py
 delete mode 100644 scripts/sbom/sbom/cmd_graph/savedcmd_parser/savedcmd_parser.py
 delete mode 100644 scripts/sbom/sbom/cmd_graph/savedcmd_parser/tokenizer.py
 delete mode 100644 scripts/sbom/tests/cmd_graph/test_savedcmd_parser.py

diff --git a/Documentation/tools/sbom/sbom.rst b/Documentation/tools/sbom/sbom.rst
index 029b08b6ad8..aada5f4875c 100644
--- a/Documentation/tools/sbom/sbom.rst
+++ b/Documentation/tools/sbom/sbom.rst
@@ -121,9 +121,9 @@ from multiple sources:
 
 * **.cmd files**: The primary source is the ``.cmd`` file of the
   generated artifact, e.g., ``arch/x86/boot/.bzImage.cmd``. These files
-  contain the exact command used to build the artifact and often include
-  an explicit list of input dependencies. By parsing the ``.cmd``
-  file, the full list of dependencies can be obtained.
+  record the shell command used to build the artifact, the make
+  prerequisites (``make_prereqs_*``), and, for compiler-generated targets,
+  additional dependencies (``deps_*``) like header files.
 
 * **.incbin statements**: The second source are include binary
   ``.incbin`` statements in ``.S`` assembly files.
@@ -188,19 +188,3 @@ In this scenario, KernelSbom does not produce a dedicated
 artifacts are included together in ``sbom-build.spdx.json``, and
 ``sbom.used-files.txt`` lists all files referenced in the build document.
 
-Unknown Build Commands
-~~~~~~~~~~~~~~~~~~~~~~
-
-Because the kernel supports a wide range of configurations and versions,
-KernelSbom may encounter build commands in ``.cmd`` files that it does
-not yet support. By default, KernelSbom will fail if an unknown build
-command is encountered.
-
-If you still wish to generate SPDX documents despite unsupported
-commands, you can use the ``--do-not-fail-on-unknown-build-command``
-option. KernelSbom will continue and produce the documents, although
-the resulting SBOM will be incomplete.
-
-This option should only be used when the missing portion of the
-dependency graph is small and an incomplete SBOM is acceptable for
-your use case.
diff --git a/scripts/sbom/sbom/cmd_graph/cmd_file.py b/scripts/sbom/sbom/cmd_graph/cmd_file.py
index ab4b00b252b..1c88854faf5 100644
--- a/scripts/sbom/sbom/cmd_graph/cmd_file.py
+++ b/scripts/sbom/sbom/cmd_graph/cmd_file.py
@@ -71,16 +71,13 @@ class CmdFile:
 
         return CmdFile(cmd_file_path, savedcmd, make_prereqs, deps)
 
-    def get_dependencies(
-        self: "CmdFile", target_path: PathStr, obj_tree: PathStr, fail_on_unknown_build_command: bool
-    ) -> list[PathStr]:
+    def get_dependencies(self: "CmdFile", target_path: PathStr, obj_tree: PathStr) -> list[PathStr]:
         """
         Parses all dependencies required to build a target file from its cmd file.
 
         Args:
             target_path: path to the target file relative to `obj_tree`.
             obj_tree: absolute path to the object tree.
-            fail_on_unknown_build_command: Whether to fail if an unknown build command is encountered.
 
         Returns:
             list[PathStr]: dependency file paths relative to `obj_tree`.
diff --git a/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py b/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py
index 61f3a8140ce..55ad5bb027d 100644
--- a/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py
+++ b/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py
@@ -23,7 +23,6 @@ class IncbinDependency:
 class CmdGraphNodeConfig(Protocol):
     obj_tree: PathStr
     src_tree: PathStr
-    fail_on_unknown_build_command: bool
 
 
 @dataclass
@@ -120,9 +119,7 @@ class CmdGraphNode:
         if cmd_file is not None:
             node.cmd_file_dependencies = [
                 _build_child_node(cmd_file_dependency_path)
-                for cmd_file_dependency_path in cmd_file.get_dependencies(
-                    target_path, config.obj_tree, config.fail_on_unknown_build_command
-                )
+                for cmd_file_dependency_path in cmd_file.get_dependencies(target_path, config.obj_tree)
             ]
 
         if node.absolute_path.endswith(".S"):
diff --git a/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py b/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py
index 2eb04d30f4e..f911fc6f23a 100644
--- a/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py
+++ b/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py
@@ -10,7 +10,6 @@ from sbom.environment import Environment
 HARDCODED_DEPENDENCIES: dict[str, list[str]] = {
     # defined in linux/Kbuild
     "include/generated/rq-offsets.h": ["kernel/sched/rq-offsets.s"],
-    "kernel/sched/rq-offsets.s": ["include/generated/asm-offsets.h"],
     "include/generated/bounds.h": ["kernel/bounds.s"],
     "include/generated/asm-offsets.h": ["arch/{arch}/kernel/asm-offsets.s"],
 }
diff --git a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/__init__.py b/scripts/sbom/sbom/cmd_graph/savedcmd_parser/__init__.py
deleted file mode 100644
index d13876af4df..00000000000
--- a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only OR MIT
-# Copyright (C) 2025 TNG Technology Consulting GmbH
-
-from sbom.cmd_graph.savedcmd_parser.savedcmd_parser import parse_inputs_from_commands
-
-__all__ = ["parse_inputs_from_commands"]
diff --git a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_parser_registry.py b/scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_parser_registry.py
deleted file mode 100644
index a48040b2c13..00000000000
--- a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_parser_registry.py
+++ /dev/null
@@ -1,516 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only OR MIT
-# Copyright (C) 2025 TNG Technology Consulting GmbH
-
-import re
-import shlex
-from typing import Callable, Iterator
-
-import sbom.sbom_logging as sbom_logging
-from sbom.environment import Environment
-from sbom.cmd_graph.savedcmd_parser.command_splitter import IfBlock, split_commands
-from sbom.cmd_graph.savedcmd_parser.tokenizer import (
-    CmdParsingError,
-    Option,
-    Positional,
-    tokenize_single_command,
-    tokenize_single_command_positionals_only,
-)
-from sbom.path_utils import PathStr
-
-CommandParser = Callable[[str], list[PathStr]]
-CommandParserRegistryEntry = tuple[re.Pattern[str], CommandParser]
-
-
-def _parse_dd_command(command: str) -> list[PathStr]:
-    match = re.match(r"dd.*?if=(\S+)", command)
-    if match:
-        return [match.group(1)]
-    return []
-
-
-def _parse_cat_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["cat", input1, input2, ...]
-    return [p for p in positionals[1:]]
-
-
-def _parse_compound_command(command: str) -> list[PathStr]:
-    compound_command_parsers: list[CommandParserRegistryEntry] = [
-        (re.compile(r"dd\b"), _parse_dd_command),
-        (re.compile(r"cat.*?\|"), lambda c: _parse_cat_command(c.split("|")[0])),
-        (re.compile(r"cat\b[^|>]*$"), _parse_cat_command),
-        (re.compile(r"echo\b"), _parse_noop),
-        (re.compile(r"\S+="), _parse_noop),
-        (re.compile(r"printf\b"), _parse_noop),
-        (re.compile(r"sed\b"), _parse_sed_command),
-        (
-            re.compile(r"(.*/)scripts/bin2c\s*<"),
-            lambda c: [input] if (input := c.split("<")[1].split(">")[0].strip()) != "/dev/null" else [],
-        ),
-        (re.compile(r"^:$"), _parse_noop),
-    ]
-
-    match = re.match(r"\s*[\(\{](.*)[\)\}]\s*>", command, re.DOTALL)
-    if match is None:
-        raise CmdParsingError("No inner commands found for compound command")
-    input_files: list[PathStr] = []
-    inner_commands = split_commands(match.group(1))
-    for inner_command in inner_commands:
-        if isinstance(inner_command, IfBlock):
-            sbom_logging.error(
-                "Skip parsing inner command {inner_command} of compound command because IfBlock is not supported",
-                inner_command=inner_command,
-            )
-            continue
-
-        parser = next((parser for pattern, parser in compound_command_parsers if pattern.match(inner_command)), None)
-        if parser is None:
-            sbom_logging.error(
-                "Skip parsing inner command {inner_command} of compound command because no matching parser was found",
-                inner_command=inner_command,
-            )
-            continue
-        try:
-            input_files += parser(inner_command)
-        except (CmdParsingError, IndexError) as e:
-            sbom_logging.error(
-                "Skip parsing inner command {inner_command} of compound command because of command parsing error: {error_message}",
-                inner_command=inner_command,
-                error_message=str(e),
-            )
-    return input_files
-
-
-def _parse_objcopy_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command, flag_options=["-S", "-w"])
-    positionals = [part.value for part in command_parts if isinstance(part, Positional)]
-    # expect positionals to be ['objcopy', input_file] or ['objcopy', input_file, output_file]
-    return [positionals[1]]
-
-
-def _parse_link_vmlinux_command(command: str) -> list[PathStr]:
-    """
-    For simplicity we do not parse the `scripts/link-vmlinux.sh` script.
-    Instead the `vmlinux.a` dependency is just hardcoded for now.
-    """
-    return ["vmlinux.a"]
-
-
-def _parse_cp_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["cp", input1, ..., destination]
-    return positionals[1:-1]
-
-
-def _parse_noop(command: str) -> list[PathStr]:
-    """
-    No-op parser for commands with no input files (e.g., 'rm', 'true').
-    Returns an empty list.
-    """
-    return []
-
-
-def _parse_ar_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ['ar', flags, output, input1, input2, ...]
-    flags = positionals[1]
-    if "r" not in flags:
-        # 'r' option indicates that new files are added to the archive.
-        # If this option is missing we won't find any relevant input files.
-        return []
-    return positionals[3:]
-
-
-def _parse_ar_piped_xargs_command(command: str) -> list[PathStr]:
-    printf_command, _ = command.split("|", 1)
-    positionals = tokenize_single_command_positionals_only(printf_command.strip())
-    # expect positionals to be ['printf', '{prefix_path}%s ', input1, input2, ...]
-    prefix_path = positionals[1].removesuffix("%s ")
-    return [f"{prefix_path}{filename}" for filename in positionals[2:]]
-
-
-def _parse_gcc_or_clang_command(command: str) -> list[PathStr]:
-    parts = shlex.split(command)
-    # compile mode: expect last positional argument ending in a source file extension to be the input file
-    for part in reversed(parts):
-        if not part.startswith("-") and any(part.endswith(suffix) for suffix in [".c", ".S", ".dts"]):
-            return [part]
-
-    # linking mode: expect all .o files to be the inputs
-    return [p for p in parts if p.endswith(".o")]
-
-
-def _parse_rustc_command(command: str) -> list[PathStr]:
-    parts = shlex.split(command)
-    # expect last positional argument ending in `.rs` to be the input file
-    for part in reversed(parts):
-        if not part.startswith("-") and part.endswith(".rs"):
-            return [part]
-    raise CmdParsingError("Could not find .rs input source file")
-
-
-def _parse_rustdoc_command(command: str) -> list[PathStr]:
-    parts = shlex.split(command)
-    # expect last positional argument ending in `.rs` to be the input file
-    for part in reversed(parts):
-        if not part.startswith("-") and part.endswith(".rs"):
-            return [part]
-    raise CmdParsingError("Could not find .rs input source file")
-
-
-def _parse_syscallhdr_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command.strip(), flag_options=["--emit-nr"])
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["sh", path/to/syscallhdr.sh, input, output]
-    return [positionals[2]]
-
-
-def _parse_syscalltbl_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command.strip())
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["sh", path/to/syscalltbl.sh, input, output]
-    return [positionals[2]]
-
-
-def _parse_mkcapflags_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["sh", path/to/mkcapflags.sh, output, input1, input2]
-    return [positionals[3], positionals[4]]
-
-
-def _parse_orc_hash_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["sh", path/to/orc_hash.sh, '<', input, '>', output]
-    return [positionals[3]]
-
-
-def _parse_xen_hypercalls_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["sh", path/to/xen-hypercalls.sh, output, input1, input2, ...]
-    return positionals[3:]
-
-
-def _parse_gen_initramfs_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command)
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["sh", path/to/gen_initramfs.sh, input1, input2, ...]
-    return positionals[2:]
-
-
-def _parse_vdso2c_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ['vdso2c', raw_input, stripped_input, output]
-    return [positionals[1], positionals[2]]
-
-
-def _parse_vdsomunge_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ['vdsomunge', input, output]
-    return [positionals[1]]
-
-
-def _parse_ld_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(
-        command=command.strip(),
-        flag_options=[
-            "-shared",
-            "--no-undefined",
-            "--eh-frame-hdr",
-            "-Bsymbolic",
-            "-r",
-            "--no-ld-generated-unwind-info",
-            "--no-dynamic-linker",
-            "-pie",
-            "--no-dynamic-linker--whole-archive",
-            "--whole-archive",
-            "--no-whole-archive",
-            "--start-group",
-            "--end-group",
-        ],
-    )
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["ld", input1, input2, ...]
-    return positionals[1:]
-
-
-def _parse_sed_command(command: str) -> list[PathStr]:
-    command_parts = shlex.split(command)
-    # expect command parts to be ["sed", *, input]
-    input = command_parts[-1]
-    if input == "/dev/null":
-        return []
-    return [input]
-
-
-def _parse_awk(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command)
-    options = [p for p in command_parts if isinstance(p, Option)]
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    has_script_file = any(p.name == "-f" for p in options)
-    # With -f option: expect ["awk", input1, input2, ...]
-    # Without -f option: expect ["awk", inline_program, input1, input2, ...]
-    return positionals[1:] if has_script_file else positionals[2:]
-
-
-def _parse_nm_piped_command(command: str) -> list[PathStr]:
-    nm_command, _ = command.split("|", 1)
-    command_parts = tokenize_single_command(
-        command=nm_command.strip(),
-        flag_options=["-p", "--defined-only"],
-    )
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["nm", input1, input2, ...]
-    return [p for p in positionals[1:]]
-
-
-def _parse_pnm_to_logo_command(command: str) -> list[PathStr]:
-    command_parts = shlex.split(command)
-    # expect command parts to be ["pnmtologo", <options>, input]
-    return [command_parts[-1]]
-
-
-def _parse_relacheck(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["relacheck", input, log_reference]
-    return [positionals[1]]
-
-
-def _parse_gen_hyprel_command(command: str) -> list[PathStr]:
-    gen_hyprel_command, _ = command.split(">", 1)
-    command_parts = shlex.split(gen_hyprel_command)
-    # expect command_parts to be ["gen-hyprel", input]
-    return [command_parts[1]]
-
-
-def _parse_perl_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command.strip())
-    # expect positionals to be ["perl", input]
-    return [positionals[1]]
-
-
-def _parse_strip_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command, flag_options=["--strip-debug"])
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["strip", input1, input2, ...]
-    return positionals[1:]
-
-
-def _parse_mkpiggy_command(command: str) -> list[PathStr]:
-    mkpiggy_command, _ = command.split(">", 1)
-    positionals = tokenize_single_command_positionals_only(mkpiggy_command)
-    # expect positionals to be ["mkpiggy", input]
-    return [positionals[1]]
-
-
-def _parse_relocs_command(command: str) -> list[PathStr]:
-    if ">" not in command:
-        # Only consider relocs commands that redirect output to a file.
-        # If there's no redirection, we assume it produces no output file and therefore has no input we care about.
-        return []
-    relocs_command, _ = command.split(">", 1)
-    command_parts = shlex.split(relocs_command)
-    # expect command_parts to be ["relocs", options, input]
-    return [command_parts[-1]]
-
-
-def _parse_mk_elfconfig_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["mk_elfconfig", "<", input, ">", output]
-    return [positionals[2]]
-
-
-def _parse_flex_command(command: str) -> list[PathStr]:
-    parts = shlex.split(command)
-    # expect last positional argument ending in `.l` to be the input file
-    for part in reversed(parts):
-        if not part.startswith("-") and part.endswith(".l"):
-            return [part]
-    raise CmdParsingError("Could not find .l input source file in command")
-
-
-def _parse_bison_command(command: str) -> list[PathStr]:
-    parts = shlex.split(command)
-    # expect last positional argument ending in `.y` to be the input file
-    for part in reversed(parts):
-        if not part.startswith("-") and part.endswith(".y"):
-            return [part]
-    raise CmdParsingError("Could not find input .y input source file in command")
-
-
-def _parse_tools_build_command(command: str) -> list[PathStr]:
-    positionals = tokenize_single_command_positionals_only(command)
-    # expect positionals to be ["tools/build", "input1", "input2", "input3", "output"]
-    return positionals[1:-1]
-
-
-def _parse_extract_cert_command(command: str) -> list[PathStr]:
-    command_parts = shlex.split(command)
-    # expect command parts to be [path/to/extract-cert, input, output]
-    input = command_parts[1]
-    if not input:
-        return []
-    return [input]
-
-
-def _parse_dtc_command(command: str) -> list[PathStr]:
-    wno_flags = [command_part for command_part in shlex.split(command) if command_part.startswith("-Wno-")]
-    command_parts = tokenize_single_command(command, flag_options=wno_flags)
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be [path/to/dtc, input]
-    return [positionals[1]]
-
-
-def _parse_bindgen_command(command: str) -> list[PathStr]:
-    command_parts = shlex.split(command)
-    header_file_input_paths = [part for part in command_parts if part.endswith(".h")]
-    return header_file_input_paths
-
-
-def _parse_gen_header(command: str) -> list[PathStr]:
-    command_parts = shlex.split(command)
-    # expect command parts to be ["python3", path/to/gen_headers.py, ..., "--xml", input]
-    i = next((i for i, token in enumerate(command_parts) if token == "--xml"), None)
-    if i is None:
-        raise CmdParsingError(f"Expected --xml input file in gen_headers command but got {command}")
-    return [command_parts[i + 1]]
-
-def _parse_mkuboot_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command)
-    # mkuboot.sh passes all args to mkimage; -d specifies the data/input image file
-    for part in command_parts:
-        if isinstance(part, Option) and part.name == "-d" and part.value is not None:
-            return [part.value]
-    raise CmdParsingError("Could not find -d (data file) option in mkuboot.sh command")
-
-
-def _parse_syscallnr_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command.strip())
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["sh", path/to/syscallnr.sh, input, output]
-    return [positionals[2]]
-
-
-def _parse_gen_kernel_hwcaps_command(command: str) -> list[PathStr]:
-    command_parts = tokenize_single_command(command.strip(), flag_options=["-e"])
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    # expect positionals to be ["sh", path/to/gen-kernel-hwcaps.sh, input]
-    return [positionals[2]]
-
-
-class CommandParserRegistry:
-    """
-    Registry mapping command patterns to their input-file parsers.
-    """
-
-    def __init__(self, entries: list[CommandParserRegistryEntry]) -> None:
-        self._entries = entries
-
-    def __iter__(self) -> Iterator[CommandParserRegistryEntry]:
-        return iter(self._entries)
-
-    @staticmethod
-    def create() -> "CommandParserRegistry":
-        def env_or_default_pattern(env_value: str | None, default_pattern: str) -> str:
-            if env_value is None or not env_value.strip():
-                return default_pattern
-            return rf"(?:{re.escape(env_value.strip())}|{default_pattern})"
-
-        cc_pattern = env_or_default_pattern(Environment.CC(), r"([^\s]+-)?(gcc|clang)")
-        ld_pattern = env_or_default_pattern(Environment.LD(), r"([^\s]+-)?ld")
-        ar_pattern = env_or_default_pattern(Environment.AR(), r"([^\s]+-)?ar")
-        nm_pattern = env_or_default_pattern(Environment.NM(), r"([^\s]+-)?nm")
-        objcopy_pattern = env_or_default_pattern(Environment.OBJCOPY(), r"([^\s]+-)?objcopy")
-        strip_pattern = env_or_default_pattern(Environment.STRIP(), r"([^\s]+-)?strip")
-
-        entries: list[CommandParserRegistryEntry] = [
-            # Compound commands
-            (re.compile(r"\(.*?\)\s*>", re.DOTALL), _parse_compound_command),
-            (re.compile(r"\{.*?\}\s*>", re.DOTALL), _parse_compound_command),
-            # Standard Unix utilities and system tools
-            (re.compile(r"^rm\b"), _parse_noop),
-            (re.compile(r"^mkdir\b"), _parse_noop),
-            (re.compile(r"^touch\b"), _parse_noop),
-            (re.compile(r"^cp\b"), _parse_cp_command),
-            (re.compile(r"^truncate\b"), _parse_noop),
-            (re.compile(r"^cat\b.*?[\|>]"), lambda c: _parse_cat_command(c.split("|")[0].split(">")[0])),
-            (re.compile(r"^echo[^|]*$"), _parse_noop),
-            (re.compile(r"^sed.*?>"), lambda c: _parse_sed_command(c.split(">")[0])),
-            (re.compile(r"^sed\b"), _parse_noop),
-            (re.compile(r"^awk.*?<.*?>"), lambda c: [c.split("<")[1].split(">")[0]]),
-            (re.compile(r"^awk.*?>"), lambda c: _parse_awk(c.split(">")[0])),
-            (re.compile(r"^(/bin/)?true\b"), _parse_noop),
-            (re.compile(r"^(/bin/)?false\b"), _parse_noop),
-            (re.compile(r"^openssl\s+req.*?-new.*?-keyout"), _parse_noop),
-            # Compilers and code generators
-            # (C/LLVM toolchain, Rust, Flex/Bison, Bindgen, Perl, etc.)
-            (
-                re.compile(rf"^{cc_pattern}\b"),
-                lambda command: _parse_gcc_or_clang_command(re.sub(rf"^{cc_pattern}\b", "gcc", command, count=1)),
-            ),
-            (
-                re.compile(rf"^{ld_pattern}\b"),
-                lambda command: _parse_ld_command(re.sub(rf"^{ld_pattern}\b", "ld", command, count=1)),
-            ),
-            (
-                re.compile(rf"^printf\b.*\| xargs {ar_pattern}\b"),
-                lambda command: _parse_ar_piped_xargs_command(
-                    re.sub(rf"xargs {ar_pattern}\b", "xargs ar", command, count=1)
-                ),
-            ),
-            (
-                re.compile(rf"^{ar_pattern}\b"),
-                lambda command: _parse_ar_command(re.sub(rf"^{ar_pattern}\b", "ar", command, count=1)),
-            ),
-            (
-                re.compile(rf"^{nm_pattern}\b.*?\|"),
-                lambda command: _parse_nm_piped_command(re.sub(rf"^{nm_pattern}\b", "nm", command, count=1)),
-            ),
-            (
-                re.compile(rf"^{objcopy_pattern}\b"),
-                lambda command: _parse_objcopy_command(re.sub(rf"^{objcopy_pattern}\b", "objcopy", command, count=1)),
-            ),
-            (
-                re.compile(rf"^{strip_pattern}\b"),
-                lambda command: _parse_strip_command(re.sub(rf"^{strip_pattern}\b", "strip", command, count=1)),
-            ),
-            (re.compile(r".*?rustc\b"), _parse_rustc_command),
-            (re.compile(r".*?rustdoc\b"), _parse_rustdoc_command),
-            (re.compile(r"^flex\b"), _parse_flex_command),
-            (re.compile(r"^bison\b"), _parse_bison_command),
-            (re.compile(r"^bindgen\b"), _parse_bindgen_command),
-            (re.compile(r"^perl\b"), _parse_perl_command),
-            # Kernel-specific build scripts and tools
-            (re.compile(r"^(.*/)?link-vmlinux\.sh\b"), _parse_link_vmlinux_command),
-            (re.compile(r"sh (.*/)?syscallhdr\.sh\b"), _parse_syscallhdr_command),
-            (re.compile(r"sh (.*/)?syscalltbl\.sh\b"), _parse_syscalltbl_command),
-            (re.compile(r"sh (.*/)?mkcapflags\.sh\b"), _parse_mkcapflags_command),
-            (re.compile(r"sh (.*/)?orc_hash\.sh\b"), _parse_orc_hash_command),
-            (re.compile(r"sh (.*/)?xen-hypercalls\.sh\b"), _parse_xen_hypercalls_command),
-            (re.compile(r"sh (.*/)?gen_initramfs\.sh\b"), _parse_gen_initramfs_command),
-            (re.compile(r"sh (.*/)?checkundef\.sh\b"), _parse_noop),
-            (re.compile(r"(bash|sh) (.*/)?mkuboot\.sh\b"), _parse_mkuboot_command),
-            (re.compile(r"sh (.*/)?syscallnr\.sh\b"), _parse_syscallnr_command),
-            (re.compile(r"(/bin/)?sh (.*/)?gen-kernel-hwcaps\.sh\b"), lambda c: _parse_gen_kernel_hwcaps_command(c.split(">")[0])),
-            (re.compile(r"(.*/)?vdso2c\b"), _parse_vdso2c_command),
-            (re.compile(r"(.*/)?vdsomunge\b"), _parse_vdsomunge_command),
-            (re.compile(r"^(.*/)?mkpiggy.*?>"), _parse_mkpiggy_command),
-            (re.compile(r"^(.*/)?relocs\b"), _parse_relocs_command),
-            (re.compile(r"^(.*/)?mk_elfconfig.*?<.*?>"), _parse_mk_elfconfig_command),
-            (re.compile(r"^(.*/)?tools/build\b"), _parse_tools_build_command),
-            (re.compile(r"^(.*/)?certs/extract-cert"), _parse_extract_cert_command),
-            (re.compile(r"^(.*/)?scripts/dtc/dtc\b"), _parse_dtc_command),
-            (re.compile(r"^(.*/)?pnmtologo\b"), _parse_pnm_to_logo_command),
-            (re.compile(r"^(.*/)?kernel/pi/relacheck"), _parse_relacheck),
-            (re.compile(r"^(.*/)?gen-hyprel\b"), _parse_gen_hyprel_command),
-            (re.compile(r"^drivers/gpu/drm/radeon/mkregtable"), lambda c: [c.split(" ")[1]]),
-            (re.compile(r"(.*/)?genheaders\b"), _parse_noop),
-            (re.compile(r"^(.*/)?mkcpustr\s+>"), _parse_noop),
-            (re.compile(r"^(.*/)polgen\b"), _parse_noop),
-            (re.compile(r"make -f .*/arch/x86/Makefile\.postlink"), _parse_noop),
-            (re.compile(r"^(.*/)?raid6/mktables\s+>"), _parse_noop),
-            (re.compile(r"^(.*/)?objtool\b"), _parse_noop),
-            (re.compile(r"^(.*/)?module/gen_test_kallsyms.sh"), _parse_noop),
-            (re.compile(r"^(.*/)?gen_header.py"), _parse_gen_header),
-            (re.compile(r"^(.*/)?scripts/rustdoc_test_gen"), _parse_noop),
-        ]
-        return CommandParserRegistry(entries)
diff --git a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_splitter.py b/scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_splitter.py
deleted file mode 100644
index 4749f4bd669..00000000000
--- a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/command_splitter.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only OR MIT
-# Copyright (C) 2025 TNG Technology Consulting GmbH
-
-import re
-from dataclasses import dataclass
-
-
-# If Block pattern to match a simple, single-level if-then-fi block. Nested If blocks are not supported.
-IF_BLOCK_PATTERN = re.compile(
-    r"""
-    ^if(.*?);\s*         # Match 'if <condition>;' (non-greedy)
-    then(.*?);\s*        # Match 'then <body>;' (non-greedy)
-    fi\b                 # Match 'fi'
-    """,
-    re.VERBOSE,
-)
-
-
-@dataclass
-class IfBlock:
-    condition: str
-    then_statement: str
-
-
-def _unwrap_outer_parentheses(s: str) -> str:
-    s = s.strip()
-    if not (s.startswith("(") and s.endswith(")")):
-        return s
-
-    count = 0
-    for i, char in enumerate(s):
-        if char == "(":
-            count += 1
-        elif char == ")":
-            count -= 1
-            # If count is 0 before the end, outer parentheses don't match
-            if count == 0 and i != len(s) - 1:
-                return s
-
-    # outer parentheses do match, unwrap once
-    return _unwrap_outer_parentheses(s[1:-1])
-
-
-def _find_first_top_level_command_separator(
-    commands: str, separators: list[str] = [";", "&&"]
-) -> tuple[int | None, int | None]:
-    def is_escaped(index: int) -> bool:
-        preceding = commands[:index]
-        return (len(preceding) - len(preceding.rstrip("\\"))) % 2 == 1
-
-    in_single_quote = False
-    in_double_quote = False
-    in_curly_braces = 0
-    in_braces = 0
-    for i, char in enumerate(commands):
-        if char == "'" and not in_double_quote and not is_escaped(i):
-            # Toggle single quote state (unless inside double quotes or escaped)
-            in_single_quote = not in_single_quote
-        elif char == '"' and not in_single_quote and not is_escaped(i):
-            # Toggle double quote state (unless inside single quotes or escaped)
-            in_double_quote = not in_double_quote
-
-        if in_single_quote or in_double_quote:
-            continue
-
-        # Toggle braces state
-        if char == "{":
-            in_curly_braces += 1
-        if char == "}":
-            in_curly_braces -= 1
-
-        if char == "(":
-            in_braces += 1
-        if char == ")":
-            in_braces -= 1
-
-        if in_curly_braces > 0 or in_braces > 0:
-            continue
-
-        # return found separator position and separator length
-        for separator in separators:
-            if commands[i : i + len(separator)] == separator:
-                return i, len(separator)
-
-    return None, None
-
-
-def split_commands(commands: str) -> list[str | IfBlock]:
-    """
-    Splits a string of command-line commands into individual parts.
-
-    This function handles:
-    - Top-level command separators (e.g., `;` and `&&`) to split multiple commands.
-    - Conditional if-blocks, returning them as `IfBlock` instances.
-    - Preserves the order of commands and trims whitespace.
-
-    Args:
-        commands (str): The raw command string.
-
-    Returns:
-        list[str | IfBlock]: A list of single commands or `IfBlock` objects.
-    """
-    single_commands: list[str | IfBlock] = []
-    remaining_commands = _unwrap_outer_parentheses(commands)
-    while len(remaining_commands) > 0:
-        remaining_commands = remaining_commands.strip()
-
-        # if block
-        matched_if = IF_BLOCK_PATTERN.match(remaining_commands)
-        if matched_if:
-            condition, then_statement = matched_if.groups()
-            single_commands.append(IfBlock(condition.strip(), then_statement.strip()))
-            full_matched = matched_if.group(0)
-            remaining_commands = remaining_commands.removeprefix(full_matched).lstrip("; \n")
-            continue
-
-        # command until next separator
-        separator_position, separator_length = _find_first_top_level_command_separator(remaining_commands)
-        if separator_position is not None and separator_length is not None:
-            single_commands.append(remaining_commands[:separator_position].strip())
-            remaining_commands = remaining_commands[separator_position + separator_length :].strip()
-            continue
-
-        # single last command
-        single_commands.append(remaining_commands)
-        break
-
-    return single_commands
diff --git a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/savedcmd_parser.py b/scripts/sbom/sbom/cmd_graph/savedcmd_parser/savedcmd_parser.py
deleted file mode 100644
index d2ca842a784..00000000000
--- a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/savedcmd_parser.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only OR MIT
-# Copyright (C) 2025 TNG Technology Consulting GmbH
-
-import sbom.sbom_logging as sbom_logging
-from sbom.cmd_graph.savedcmd_parser.command_splitter import IfBlock, split_commands
-from sbom.cmd_graph.savedcmd_parser.command_parser_registry import CommandParserRegistry
-from sbom.cmd_graph.savedcmd_parser.tokenizer import CmdParsingError
-from sbom.path_utils import PathStr
-
-DEFAULT_COMMAND_PARSER_REGISTRY = CommandParserRegistry.create()
-
-
-def parse_inputs_from_commands(
-    commands: str,
-    fail_on_unknown_build_command: bool,
-    registry: CommandParserRegistry | None = None,
-) -> list[PathStr]:
-    """
-    Extract input files referenced in a set of command-line commands.
-
-    Args:
-        commands (str): Command line expression to parse.
-        fail_on_unknown_build_command (bool): Whether to fail if an unknown build command is encountered. If False, errors are logged as warnings.
-        registry (CommandParserRegistry | None): Registry of single command parsers.
-
-    Returns:
-        list[PathStr]: List of input file paths required by the commands.
-    """
-
-    def log_error_or_warning(message: str, /, **kwargs: str) -> None:
-        if fail_on_unknown_build_command:
-            sbom_logging.error(message, **kwargs)
-        else:
-            sbom_logging.warning(message, **kwargs)
-
-    if registry is None:
-        registry = DEFAULT_COMMAND_PARSER_REGISTRY
-
-    input_files: list[PathStr] = []
-    for single_command in split_commands(commands):
-        if isinstance(single_command, IfBlock):
-            inputs = parse_inputs_from_commands(single_command.then_statement, fail_on_unknown_build_command, registry)
-            if inputs:
-                log_error_or_warning(
-                    "Skipped parsing command {then_statement} because input files in IfBlock 'then' statement are not supported",
-                    then_statement=single_command.then_statement,
-                )
-            continue
-
-        matched_parser = next((parser for pattern, parser in registry if pattern.match(single_command)), None)
-        if matched_parser is None:
-            log_error_or_warning(
-                "Skipped parsing command {single_command} because no matching parser was found",
-                single_command=single_command,
-            )
-            continue
-        try:
-            inputs = matched_parser(single_command)
-            input_files.extend(inputs)
-        except (CmdParsingError, IndexError, ValueError) as e:
-            log_error_or_warning(
-                "Skipped parsing command {single_command} because of command parsing error: {error_message}",
-                single_command=single_command,
-                error_message=str(e),
-            )
-
-    return [input.strip().rstrip("/") for input in input_files]
diff --git a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/tokenizer.py b/scripts/sbom/sbom/cmd_graph/savedcmd_parser/tokenizer.py
deleted file mode 100644
index 1bf081f40be..00000000000
--- a/scripts/sbom/sbom/cmd_graph/savedcmd_parser/tokenizer.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only OR MIT
-# Copyright (C) 2025 TNG Technology Consulting GmbH
-
-import re
-import shlex
-from dataclasses import dataclass
-from typing import Union
-
-
-class CmdParsingError(Exception):
-    pass
-
-
-@dataclass
-class Option:
-    name: str
-    value: str | None = None
-
-
-@dataclass
-class Positional:
-    value: str
-
-
-_SUBCOMMAND_PATTERN = re.compile(r"\$\$\(([^()]*)\)")
-"""Pattern to match $$(...) blocks"""
-
-
-def tokenize_single_command(command: str, flag_options: list[str] | None = None) -> list[Union[Option, Positional]]:
-    """
-    Parse a shell command into a list of Options and Positionals.
-    - Positional: the command and any positional arguments.
-    - Options: handles flags and options with values provided as space-separated, or equals-sign
-        (e.g., '--opt val', '--opt=val', '--flag').
-
-    Args:
-        command: Command line string.
-        flag_options: Options that are flags without values (e.g., '--verbose').
-
-    Returns:
-        List of `Option` and `Positional` objects in command order.
-    """
-
-    #  Wrap all $$(...) blocks in double quotes to prevent shlex from splitting them.
-    command_with_protected_subcommands = _SUBCOMMAND_PATTERN.sub(lambda m: f'"$$({m.group(1)})"', command)
-    tokens = shlex.split(command_with_protected_subcommands)
-
-    parsed: list[Option | Positional] = []
-    i = 0
-    while i < len(tokens):
-        token = tokens[i]
-
-        # Positional
-        if not token.startswith("-"):
-            parsed.append(Positional(token))
-            i += 1
-            continue
-
-        # Option without value (--flag)
-        if (token.startswith("-") and i + 1 < len(tokens) and tokens[i + 1].startswith("-")) or (
-            flag_options and token in flag_options
-        ):
-            parsed.append(Option(name=token))
-            i += 1
-            continue
-
-        # Option with equals sign (--opt=val)
-        if "=" in token:
-            name, value = token.split("=", 1)
-            parsed.append(Option(name=name, value=value))
-            i += 1
-            continue
-
-        # Option with space-separated value (--opt val)
-        if i + 1 < len(tokens) and not tokens[i + 1].startswith("-"):
-            parsed.append(Option(name=token, value=tokens[i + 1]))
-            i += 2
-            continue
-
-        raise CmdParsingError(f"Unrecognized token: {token} in command {command}")
-
-    return parsed
-
-
-def tokenize_single_command_positionals_only(command: str) -> list[str]:
-    command_parts = tokenize_single_command(command)
-    positionals = [p.value for p in command_parts if isinstance(p, Positional)]
-    if len(positionals) != len(command_parts):
-        raise CmdParsingError(
-            f"Invalid command format: expected positional arguments only but got options in command {command}."
-        )
-    return positionals
diff --git a/scripts/sbom/sbom/config.py b/scripts/sbom/sbom/config.py
index 6811f782943..08474c2bfc3 100644
--- a/scripts/sbom/sbom/config.py
+++ b/scripts/sbom/sbom/config.py
@@ -47,9 +47,6 @@ class KernelSbomConfig:
     debug: bool
     """Whether to enable debug logging."""
 
-    fail_on_unknown_build_command: bool
-    """Whether to fail if an unknown build command is encountered in a .cmd file."""
-
     write_output_on_error: bool
     """Whether to write output documents even if errors occur."""
 
@@ -141,15 +138,6 @@ def _parse_cli_arguments(parser: argparse.ArgumentParser) -> dict[str, Any]:
     )
 
     # Error handling settings
-    parser.add_argument(
-        "--do-not-fail-on-unknown-build-command",
-        action="store_true",
-        default=False,
-        help=(
-            "Whether to fail if an unknown build command is encountered in a .cmd file.\n"
-            "If set to True, errors are logged as warnings instead. (default: False)"
-        ),
-    )
     parser.add_argument(
         "--write-output-on-error",
         action="store_true",
@@ -245,7 +233,6 @@ def get_config() -> KernelSbomConfig:
     output_directory = os.path.realpath(args["output_directory"])
     debug = args["debug"]
 
-    fail_on_unknown_build_command = not args["do_not_fail_on_unknown_build_command"]
     write_output_on_error = args["write_output_on_error"]
 
     created = datetime.fromtimestamp(
@@ -283,7 +270,6 @@ def get_config() -> KernelSbomConfig:
         used_files_file_name=used_files_file_name,
         output_directory=output_directory,
         debug=debug,
-        fail_on_unknown_build_command=fail_on_unknown_build_command,
         write_output_on_error=write_output_on_error,
         created=created,
         spdxId_prefix=spdxId_prefix,
diff --git a/scripts/sbom/tests/cmd_graph/test_savedcmd_parser.py b/scripts/sbom/tests/cmd_graph/test_savedcmd_parser.py
deleted file mode 100644
index d7776f072e0..00000000000
--- a/scripts/sbom/tests/cmd_graph/test_savedcmd_parser.py
+++ /dev/null
@@ -1,468 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only OR MIT
-# Copyright (C) 2025 TNG Technology Consulting GmbH
-
-import os
-import unittest
-from unittest.mock import patch
-
-from sbom.cmd_graph.savedcmd_parser import parse_inputs_from_commands
-from sbom.cmd_graph.savedcmd_parser.command_parser_registry import CommandParserRegistry
-import sbom.sbom_logging as sbom_logging
-
-
-class TestSavedCmdParser(unittest.TestCase):
-    def _assert_parsing(self, cmd: str, expected: str, registry: CommandParserRegistry | None = None) -> None:
-        sbom_logging.init()
-        parsed = parse_inputs_from_commands(cmd, fail_on_unknown_build_command=False, registry=registry)
-        target = [] if expected == "" else expected.split(" ")
-        self.assertEqual(parsed, target)
-        errors = sbom_logging._error_logger._message_counts # type: ignore
-        self.assertEqual(errors, {})
-
-    # Error handling tests
-    def test_malformed_shell_quoting(self):
-        command = 'gcc "unterminated'
-        with patch.object(sbom_logging, "warning") as warning:
-            parsed = parse_inputs_from_commands(command, fail_on_unknown_build_command=False)
-
-        self.assertEqual(parsed, [])
-        warning.assert_called_once_with(
-            "Skipped parsing command {single_command} because of command parsing error: {error_message}",
-            single_command=command,
-            error_message="No closing quotation",
-        )
-
-    def test_missing_positional_argument(self):
-        command = "objcopy"
-        with patch.object(sbom_logging, "warning") as warning:
-            parsed = parse_inputs_from_commands(command, fail_on_unknown_build_command=False)
-
-        self.assertEqual(parsed, [])
-        warning.assert_called_once_with(
-            "Skipped parsing command {single_command} because of command parsing error: {error_message}",
-            single_command=command,
-            error_message="list index out of range",
-        )
-
-    # Compound command tests
-    def test_dd_cat(self):
-        cmd = "(dd if=arch/x86/boot/setup.bin bs=4k conv=sync status=none; cat arch/x86/boot/vmlinux.bin) >arch/x86/boot/bzImage"
-        expected = "arch/x86/boot/setup.bin arch/x86/boot/vmlinux.bin"
-        self._assert_parsing(cmd, expected)
-
-    def test_manual_file_creation(self):
-        cmd = """{ symbase=__dtbo_overlay_bad_unresolved; echo '$(pound)include <asm-generic/vmlinux.lds.h>'; echo '.section .rodata,"a"'; echo '.balign STRUCT_ALIGNMENT'; echo ".global $${symbase}_begin"; echo "$${symbase}_begin:"; echo '.incbin "drivers/of/unittest-data/overlay_bad_unresolved.dtbo" '; echo ".global $${symbase}_end"; echo "$${symbase}_end:"; echo '.balign STRUCT_ALIGNMENT'; } > drivers/of/unittest-data/overlay_bad_unresolved.dtbo.S"""
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    def test_cat_xz_wrap(self):
-        cmd = "{ cat arch/x86/boot/compressed/vmlinux.bin | sh ../scripts/xz_wrap.sh; printf \\130\\064\\024\\000; } > arch/x86/boot/compressed/vmlinux.bin.xz"
-        expected = "arch/x86/boot/compressed/vmlinux.bin"
-        self._assert_parsing(cmd, expected)
-
-    def test_printf_sed(self):
-        cmd = r"""{  printf 'static char tomoyo_builtin_profile[] __initdata =\n'; sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/\t"\1\\n"/' -- /dev/null; printf '\t"";\n';  printf 'static char tomoyo_builtin_exception_policy[] __initdata =\n'; sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/\t"\1\\n"/' -- ../security/tomoyo/policy/exception_policy.conf.default; printf '\t"";\n';  printf 'static char tomoyo_builtin_domain_policy[] __initdata =\n'; sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/\t"\1\\n"/' -- /dev/null; printf '\t"";\n';  printf 'static char tomoyo_builtin_manager[] __initdata =\n'; sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/\t"\1\\n"/' -- /dev/null; printf '\t"";\n';  printf 'static char tomoyo_builtin_stat[] __initdata =\n'; sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/\t"\1\\n"/' -- /dev/null; printf '\t"";\n'; } > security/tomoyo/builtin-policy.h"""
-        expected = "../security/tomoyo/policy/exception_policy.conf.default"
-        self._assert_parsing(cmd, expected)
-
-    def test_bin2c_echo(self):
-        cmd = """(echo "static char tomoyo_builtin_profile[] __initdata ="; ./scripts/bin2c </dev/null; echo ";"; echo "static char tomoyo_builtin_exception_policy[] __initdata ="; ./scripts/bin2c <../security/tomoyo/policy/exception_policy.conf.default; echo ";"; echo "static char tomoyo_builtin_domain_policy[] __initdata ="; ./scripts/bin2c </dev/null; echo ";"; echo "static char tomoyo_builtin_manager[] __initdata ="; ./scripts/bin2c </dev/null; echo ";"; echo "static char tomoyo_builtin_stat[] __initdata ="; ./scripts/bin2c </dev/null; echo ";") >security/tomoyo/builtin-policy.h"""
-        expected = "../security/tomoyo/policy/exception_policy.conf.default"
-        self._assert_parsing(cmd, expected)
-
-    def test_cat_colon(self):
-        cmd = "{   cat init/modules.order;   cat usr/modules.order;   cat arch/x86/modules.order;   cat arch/x86/boot/startup/modules.order;   cat kernel/modules.order;   cat certs/modules.order;   cat mm/modules.order;   cat fs/modules.order;   cat ipc/modules.order;   cat security/modules.order;   cat crypto/modules.order;   cat block/modules.order;   cat io_uring/modules.order;   cat lib/modules.order;   cat arch/x86/lib/modules.order;   cat drivers/modules.order;   cat sound/modules.order;   cat samples/modules.order;   cat net/modules.order;   cat virt/modules.order;   cat arch/x86/pci/modules.order;   cat arch/x86/power/modules.order;   cat arch/x86/video/modules.order; :; } > modules.order"
-        expected = "init/modules.order usr/modules.order arch/x86/modules.order arch/x86/boot/startup/modules.order kernel/modules.order certs/modules.order mm/modules.order fs/modules.order ipc/modules.order security/modules.order crypto/modules.order block/modules.order io_uring/modules.order lib/modules.order arch/x86/lib/modules.order drivers/modules.order sound/modules.order samples/modules.order net/modules.order virt/modules.order arch/x86/pci/modules.order arch/x86/power/modules.order arch/x86/video/modules.order"
-        self._assert_parsing(cmd, expected)
-
-    def test_cat_zstd(self):
-        cmd = "{ cat arch/x86/boot/compressed/vmlinux.bin arch/x86/boot/compressed/vmlinux.relocs | zstd -22 --ultra; printf \\340\\362\\066\\003; } > arch/x86/boot/compressed/vmlinux.bin.zst"
-        expected = "arch/x86/boot/compressed/vmlinux.bin arch/x86/boot/compressed/vmlinux.relocs"
-        self._assert_parsing(cmd, expected)
-
-    # cat command tests
-    def test_cat_redirect(self):
-        cmd = "cat ../fs/unicode/utf8data.c_shipped > fs/unicode/utf8data.c"
-        expected = "../fs/unicode/utf8data.c_shipped"
-        self._assert_parsing(cmd, expected)
-
-    def test_cat_piped(self):
-        cmd = "cat arch/x86/boot/compressed/vmlinux.bin arch/x86/boot/compressed/vmlinux.relocs | gzip -n -f -9 > arch/x86/boot/compressed/vmlinux.bin.gz"
-        expected = "arch/x86/boot/compressed/vmlinux.bin arch/x86/boot/compressed/vmlinux.relocs"
-        self._assert_parsing(cmd, expected)
-
-    # sed command tests
-    def test_sed(self):
-        cmd = "sed -n 's/.*define *BLIST_\\([A-Z0-9_]*\\) *.*/BLIST_FLAG_NAME(\\1),/p' ../include/scsi/scsi_devinfo.h > drivers/scsi/scsi_devinfo_tbl.c"
-        expected = "../include/scsi/scsi_devinfo.h"
-        self._assert_parsing(cmd, expected)
-
-    # awk command tests
-    def test_awk(self):
-        cmd = "awk -f ../arch/arm64/tools/gen-cpucaps.awk ../arch/arm64/tools/cpucaps > arch/arm64/include/generated/asm/cpucap-defs.h"
-        expected = "../arch/arm64/tools/cpucaps"
-        self._assert_parsing(cmd, expected)
-
-    def test_awk_with_input_redirection(self):
-        cmd = "awk -v N=1 -f ../lib/raid6/unroll.awk < ../lib/raid6/int.uc > lib/raid6/int1.c"
-        expected = "../lib/raid6/int.uc"
-        self._assert_parsing(cmd, expected)
-
-    # openssl command tests
-    def test_openssl(self):
-        cmd = "openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 -config certs/x509.genkey -outform PEM -out certs/signing_key.pem -keyout certs/signing_key.pem  2>&1"
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # gcc/clang command tests
-    def test_gcc(self):
-        cmd = (
-            "gcc -Wp,-MMD,arch/x86/pci/.i386.o.d -nostdinc -I../arch/x86/include -I./arch/x86/include/generated -I../include -I./include -I../arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I../include/uapi -I./include/generated/uapi -include ../include/linux/compiler-version.h -include ../include/linux/kconfig.h -include ../include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=../= -Werror -std=gnu11 -fshort-wchar -funsigned-char -fno-common -fno-PIE -fno-strict-aliasing -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=branch -fno-jump-tables -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -march=x86-64 -mtune=generic -mno-red-zone -mcmodel=kernel -mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__ref_stack_chk_guard -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -fno-jump-tables -fpatchable-function-entry=16,16 -fno-delete-null-pointer-checks -O2 -fno-allow-store-data-races -fstack-protector-strong -fomit-frame-pointer -fno-stack-clash-protection -falign-functions=16 -fno-strict-overflow -fno-stack-check -fconserve-stack -fno-builtin-wcslen -Wall -Wextra -Wundef -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Werror=strict-prototypes -Wno-format-security -Wno-trigraphs -Wno-frame-address -Wno-address-of-packed-member -Wmissing-declarations -Wmissing-prototypes -Wframe-larger-than=2048 -Wno-main -Wvla-larger-than=1 -Wno-pointer-sign -Wcast-function-type -Wno-array-bounds -Wno-stringop-overflow -Wno-alloc-size-larger-than -Wimplicit-fallthrough=5 -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -Wenum-conversion -Wunused -Wno-unused-but-set-variable -Wno-unused-const-variable -Wno-packed-not-aligned -Wno-format-overflow -Wno-format-truncation -Wno-stringop-truncation -Wno-override-init -Wno-missing-field-initializers -Wno-type-limits -Wno-shift-negative-value -Wno-maybe-uninitialized -Wno-sign-compare -Wno-unused-parameter -I../arch/x86/pci -Iarch/x86/pci    -DKBUILD_MODFILE="
-            "arch/x86/pci/i386"
-            " -DKBUILD_BASENAME="
-            "i386"
-            " -DKBUILD_MODNAME="
-            "i386"
-            " -D__KBUILD_MODNAME=kmod_i386 -c -o arch/x86/pci/i386.o ../arch/x86/pci/i386.c  "
-        )
-        expected = "../arch/x86/pci/i386.c"
-        self._assert_parsing(cmd, expected)
-
-    def test_gcc_linking(self):
-        cmd = "gcc   -o arch/x86/tools/relocs arch/x86/tools/relocs_32.o arch/x86/tools/relocs_64.o arch/x86/tools/relocs_common.o"
-        expected = "arch/x86/tools/relocs_32.o arch/x86/tools/relocs_64.o arch/x86/tools/relocs_common.o"
-        self._assert_parsing(cmd, expected)
-
-    def test_gcc_without_compile_flag(self):
-        cmd = "gcc -Wp,-MMD,arch/x86/boot/compressed/.mkpiggy.d -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu11   -I ../scripts/include -I../tools/include  -I arch/x86/boot/compressed   -o arch/x86/boot/compressed/mkpiggy ../arch/x86/boot/compressed/mkpiggy.c"
-        expected = "../arch/x86/boot/compressed/mkpiggy.c"
-        self._assert_parsing(cmd, expected)
-
-    def test_gcc_with_env_override(self):
-        with patch.dict(os.environ, {"CC": "ccache gcc"}):
-            registry = CommandParserRegistry.create()
-            cmd = "gcc   -o arch/x86/tools/relocs arch/x86/tools/relocs_32.o arch/x86/tools/relocs_64.o arch/x86/tools/relocs_common.o"
-            expected = "arch/x86/tools/relocs_32.o arch/x86/tools/relocs_64.o arch/x86/tools/relocs_common.o"
-            self._assert_parsing(cmd, expected, registry)
-            self._assert_parsing(f"ccache {cmd}", expected, registry)
-
-    def test_gcc_dts_preprocessing(self):
-        cmd = "gcc -E -Wp,-MMD,drivers/of/.empty_root.dtb.d.pre.tmp -nostdinc -I ../scripts/dtc/include-prefixes -undef -D__DTS__ -x assembler-with-cpp -o drivers/of/.empty_root.dtb.dts.tmp ../drivers/of/empty_root.dts"
-        expected = "../drivers/of/empty_root.dts"
-        self._assert_parsing(cmd, expected)
-
-    def test_clang(self):
-        cmd = """clang -Wp,-MMD,arch/x86/entry/.entry_64_compat.o.d -nostdinc -I../arch/x86/include -I./arch/x86/include/generated -I../include -I./include -I../arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I../include/uapi -I./include/generated/uapi -include ../include/linux/compiler-version.h -include ../include/linux/kconfig.h -D__KERNEL__ --target=x86_64-linux-gnu -fintegrated-as -Werror=unknown-warning-option -Werror=ignored-optimization-argument -Werror=option-ignored -Werror=unused-command-line-argument -fmacro-prefix-map=../= -Werror -D__ASSEMBLY__ -fno-PIE -m64 -I../arch/x86/entry -Iarch/x86/entry    -DKBUILD_MODFILE='"arch/x86/entry/entry_64_compat"' -DKBUILD_MODNAME='"entry_64_compat"' -D__KBUILD_MODNAME=kmod_entry_64_compat -c -o arch/x86/entry/entry_64_compat.o ../arch/x86/entry/entry_64_compat.S"""
-        expected = "../arch/x86/entry/entry_64_compat.S"
-        self._assert_parsing(cmd, expected)
-
-    # ld command tests
-    def test_ld(self):
-        cmd = r'ld -o arch/x86/entry/vdso/vdso64.so.dbg -shared --hash-style=both --build-id=sha1 --no-undefined  --eh-frame-hdr -Bsymbolic -z noexecstack -m elf_x86_64 -soname linux-vdso.so.1 -z max-page-size=4096 -T arch/x86/entry/vdso/vdso.lds arch/x86/entry/vdso/vdso-note.o arch/x86/entry/vdso/vclock_gettime.o arch/x86/entry/vdso/vgetcpu.o arch/x86/entry/vdso/vgetrandom.o arch/x86/entry/vdso/vgetrandom-chacha.o; if readelf -rW arch/x86/entry/vdso/vdso64.so.dbg | grep -v _NONE | grep -q " R_\w*_"; then (echo >&2 "arch/x86/entry/vdso/vdso64.so.dbg: dynamic relocations are not supported"; rm -f arch/x86/entry/vdso/vdso64.so.dbg; /bin/false); fi'
-        expected = "arch/x86/entry/vdso/vdso-note.o arch/x86/entry/vdso/vclock_gettime.o arch/x86/entry/vdso/vgetcpu.o arch/x86/entry/vdso/vgetrandom.o arch/x86/entry/vdso/vgetrandom-chacha.o"
-        self._assert_parsing(cmd, expected)
-
-    def test_ld_with_env_override(self):
-        with patch.dict(os.environ, {"LD": "some-tool ld"}):
-            registry = CommandParserRegistry.create()
-            cmd = r'ld -o arch/x86/entry/vdso/vdso64.so.dbg -shared --hash-style=both --build-id=sha1 --no-undefined  --eh-frame-hdr -Bsymbolic -z noexecstack -m elf_x86_64 -soname linux-vdso.so.1 -z max-page-size=4096 -T arch/x86/entry/vdso/vdso.lds arch/x86/entry/vdso/vdso-note.o arch/x86/entry/vdso/vclock_gettime.o arch/x86/entry/vdso/vgetcpu.o arch/x86/entry/vdso/vgetrandom.o arch/x86/entry/vdso/vgetrandom-chacha.o; if readelf -rW arch/x86/entry/vdso/vdso64.so.dbg | grep -v _NONE | grep -q " R_\w*_"; then (echo >&2 "arch/x86/entry/vdso/vdso64.so.dbg: dynamic relocations are not supported"; rm -f arch/x86/entry/vdso/vdso64.so.dbg; /bin/false); fi'
-            expected = "arch/x86/entry/vdso/vdso-note.o arch/x86/entry/vdso/vclock_gettime.o arch/x86/entry/vdso/vgetcpu.o arch/x86/entry/vdso/vgetrandom.o arch/x86/entry/vdso/vgetrandom-chacha.o"
-            self._assert_parsing(cmd, expected, registry)
-            self._assert_parsing(f"some-tool {cmd}", expected, registry)
-
-    def test_ld_whole_archive(self):
-        cmd = "ld -m elf_x86_64 -z noexecstack -r -o vmlinux.o   --whole-archive vmlinux.a --no-whole-archive --start-group  --end-group"
-        expected = "vmlinux.a"
-        self._assert_parsing(cmd, expected)
-
-    def test_ld_with_at_symbol(self):
-        cmd = "ld.lld -m elf_x86_64 -z noexecstack   -r -o fs/efivarfs/efivarfs.o @fs/efivarfs/efivarfs.mod  ; ./tools/objtool/objtool --hacks=jump_label --hacks=noinstr --hacks=skylake --ibt --orc --retpoline --rethunk --static-call --uaccess --prefix=16  --link  --module fs/efivarfs/efivarfs.o"
-        expected = "@fs/efivarfs/efivarfs.mod"
-        self._assert_parsing(cmd, expected)
-
-    def test_ld_if_objdump(self):
-        cmd = """ld -o arch/x86/entry/vdso/vdso64.so.dbg -shared --hash-style=both --build-id=sha1  --eh-frame-hdr -Bsymbolic -z noexecstack -m elf_x86_64 -soname linux-vdso.so.1 --no-undefined -z max-page-size=4096 -T arch/x86/entry/vdso/vdso.lds arch/x86/entry/vdso/vdso-note.o arch/x86/entry/vdso/vclock_gettime.o arch/x86/entry/vdso/vgetcpu.o arch/x86/entry/vdso/vsgx.o && sh ./arch/x86/entry/vdso/checkundef.sh 'nm' 'arch/x86/entry/vdso/vdso64.so.dbg'; if objdump -R arch/x86/entry/vdso/vdso64.so.dbg | grep -E -h "R_X86_64_JUMP_SLOT|R_X86_64_GLOB_DAT|R_X86_64_RELATIVE| R_386_GLOB_DAT|R_386_JMP_SLOT|R_386_RELATIVE"; then (echo >&2 "arch/x86/entry/vdso/vdso64.so.dbg: dynamic relocations are not supported"; rm -f arch/x86/entry/vdso/vdso64.so.dbg; /bin/false); fi"""
-        expected = "arch/x86/entry/vdso/vdso-note.o arch/x86/entry/vdso/vclock_gettime.o arch/x86/entry/vdso/vgetcpu.o arch/x86/entry/vdso/vsgx.o"
-        self._assert_parsing(cmd, expected)
-
-    # printf | xargs ar command tests
-    def test_ar_printf(self):
-        cmd = 'rm -f built-in.a;  printf "./%s " init/built-in.a usr/built-in.a arch/x86/built-in.a arch/x86/boot/startup/built-in.a kernel/built-in.a certs/built-in.a mm/built-in.a fs/built-in.a ipc/built-in.a security/built-in.a crypto/built-in.a block/built-in.a io_uring/built-in.a lib/built-in.a arch/x86/lib/built-in.a drivers/built-in.a sound/built-in.a net/built-in.a virt/built-in.a arch/x86/pci/built-in.a arch/x86/power/built-in.a arch/x86/video/built-in.a | xargs ar cDPrST built-in.a'
-        expected = "./init/built-in.a ./usr/built-in.a ./arch/x86/built-in.a ./arch/x86/boot/startup/built-in.a ./kernel/built-in.a ./certs/built-in.a ./mm/built-in.a ./fs/built-in.a ./ipc/built-in.a ./security/built-in.a ./crypto/built-in.a ./block/built-in.a ./io_uring/built-in.a ./lib/built-in.a ./arch/x86/lib/built-in.a ./drivers/built-in.a ./sound/built-in.a ./net/built-in.a ./virt/built-in.a ./arch/x86/pci/built-in.a ./arch/x86/power/built-in.a ./arch/x86/video/built-in.a"
-        self._assert_parsing(cmd, expected)
-
-    def test_ar_printf_nested(self):
-        cmd = 'rm -f arch/x86/pci/built-in.a;  printf "arch/x86/pci/%s " i386.o init.o mmconfig_64.o direct.o mmconfig-shared.o fixup.o acpi.o legacy.o irq.o common.o early.o bus_numa.o amd_bus.o | xargs ar cDPrST arch/x86/pci/built-in.a'
-        expected = "arch/x86/pci/i386.o arch/x86/pci/init.o arch/x86/pci/mmconfig_64.o arch/x86/pci/direct.o arch/x86/pci/mmconfig-shared.o arch/x86/pci/fixup.o arch/x86/pci/acpi.o arch/x86/pci/legacy.o arch/x86/pci/irq.o arch/x86/pci/common.o arch/x86/pci/early.o arch/x86/pci/bus_numa.o arch/x86/pci/amd_bus.o"
-        self._assert_parsing(cmd, expected)
-
-    # ar command tests
-    def test_ar_reordering(self):
-        cmd = "rm -f vmlinux.a; ar cDPrST vmlinux.a built-in.a  lib/lib.a arch/x86/lib/lib.a; ar mPiT $$(ar t vmlinux.a | sed -n 1p) vmlinux.a $$(ar t vmlinux.a | grep -F -f ../scripts/head-object-list.txt)"
-        expected = "built-in.a lib/lib.a arch/x86/lib/lib.a"
-        self._assert_parsing(cmd, expected)
-
-    def test_ar_default(self):
-        cmd = "rm -f lib/lib.a; ar cDPrsT lib/lib.a lib/argv_split.o lib/bug.o lib/buildid.o lib/clz_tab.o lib/cmdline.o lib/cpumask.o lib/ctype.o lib/dec_and_lock.o lib/decompress.o lib/decompress_bunzip2.o lib/decompress_inflate.o lib/decompress_unlz4.o lib/decompress_unlzma.o lib/decompress_unlzo.o lib/decompress_unxz.o lib/decompress_unzstd.o lib/dump_stack.o lib/earlycpio.o lib/extable.o lib/flex_proportions.o lib/idr.o lib/iomem_copy.o lib/irq_regs.o lib/is_single_threaded.o lib/klist.o lib/kobject.o lib/kobject_uevent.o lib/logic_pio.o lib/maple_tree.o lib/memcat_p.o lib/nmi_backtrace.o lib/objpool.o lib/plist.o lib/radix-tree.o lib/ratelimit.o lib/rbtree.o lib/seq_buf.o lib/siphash.o lib/string.o lib/sys_info.o lib/timerqueue.o lib/union_find.o lib/vsprintf.o lib/win_minmax.o lib/xarray.o"
-        expected = "lib/argv_split.o lib/bug.o lib/buildid.o lib/clz_tab.o lib/cmdline.o lib/cpumask.o lib/ctype.o lib/dec_and_lock.o lib/decompress.o lib/decompress_bunzip2.o lib/decompress_inflate.o lib/decompress_unlz4.o lib/decompress_unlzma.o lib/decompress_unlzo.o lib/decompress_unxz.o lib/decompress_unzstd.o lib/dump_stack.o lib/earlycpio.o lib/extable.o lib/flex_proportions.o lib/idr.o lib/iomem_copy.o lib/irq_regs.o lib/is_single_threaded.o lib/klist.o lib/kobject.o lib/kobject_uevent.o lib/logic_pio.o lib/maple_tree.o lib/memcat_p.o lib/nmi_backtrace.o lib/objpool.o lib/plist.o lib/radix-tree.o lib/ratelimit.o lib/rbtree.o lib/seq_buf.o lib/siphash.o lib/string.o lib/sys_info.o lib/timerqueue.o lib/union_find.o lib/vsprintf.o lib/win_minmax.o lib/xarray.o"
-        self._assert_parsing(cmd, expected)
-
-    def test_ar_llvm(self):
-        cmd = "llvm-ar mPiT $$(llvm-ar t vmlinux.a | sed -n 1p) vmlinux.a $$(llvm-ar t vmlinux.a | grep -F -f ../scripts/head-object-list.txt)"
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # nm command tests
-    def test_nm(self):
-        cmd = """llvm-nm -p --defined-only rust/core.o | awk '$$2~/(T|R|D|B)/ && $$3!~/__(pfx|cfi|odr_asan)/ { printf "EXPORT_SYMBOL_RUST_GPL(%s);\n",$$3 }' > rust/exports_core_generated.h"""
-        expected = "rust/core.o"
-        self._assert_parsing(cmd, expected)
-
-    def test_nm_vmlinux(self):
-        cmd = r"nm vmlinux | sed -n -e 's/^\([0-9a-fA-F]*\) [ABbCDGRSTtVW] \(_text\|__start_rodata\|__bss_start\|_end\)$/#define VO_\2 _AC(0x\1,UL)/p' > arch/x86/boot/voffset.h"
-        expected = "vmlinux"
-        self._assert_parsing(cmd, expected)
-
-    # objcopy command tests
-    def test_objcopy(self):
-        cmd = "objcopy --remove-section='.rel*' --remove-section=!'.rel*.dyn' vmlinux.unstripped vmlinux"
-        expected = "vmlinux.unstripped"
-        self._assert_parsing(cmd, expected)
-
-    def test_objcopy_llvm(self):
-        cmd = "llvm-objcopy --remove-section='.rel*' --remove-section=!'.rel*.dyn' vmlinux.unstripped vmlinux"
-        expected = "vmlinux.unstripped"
-        self._assert_parsing(cmd, expected)
-
-    # strip command tests
-    def test_strip(self):
-        cmd = "strip --strip-debug -o drivers/firmware/efi/libstub/mem.stub.o drivers/firmware/efi/libstub/mem.o"
-        expected = "drivers/firmware/efi/libstub/mem.o"
-        self._assert_parsing(cmd, expected)
-
-    # cp command tests
-    def test_cp_truncate(self):
-        cmd = "cp arch/arm64/boot/Image arch/arm64/boot/vmlinux.bin; truncate -s $$(hexdump -s16 -n4 -e '\"%u\"' arch/arm64/boot/Image) arch/arm64/boot/vmlinux.bin"
-        expected = "arch/arm64/boot/Image"
-        self._assert_parsing(cmd, expected)
-
-    # rustc command tests
-    def test_rustc(self):
-        cmd = """OBJTREE=/workspace/linux/kernel_build rustc -Zbinary_dep_depinfo=y -Astable_features -Dnon_ascii_idents -Dunsafe_op_in_unsafe_fn -Wmissing_docs -Wrust_2018_idioms -Wclippy::all -Wclippy::as_ptr_cast_mut -Wclippy::as_underscore -Wclippy::cast_lossless -Wclippy::ignored_unit_patterns -Wclippy::mut_mut -Wclippy::needless_bitwise_bool -Aclippy::needless_lifetimes -Wclippy::no_mangle_with_rust_abi -Wclippy::ptr_as_ptr -Wclippy::ptr_cast_constness -Wclippy::ref_as_ptr -Wclippy::undocumented_unsafe_blocks -Wclippy::unnecessary_safety_comment -Wclippy::unnecessary_safety_doc -Wrustdoc::missing_crate_level_docs -Wrustdoc::unescaped_backticks -Cpanic=abort -Cembed-bitcode=n -Clto=n -Cforce-unwind-tables=n -Ccodegen-units=1 -Csymbol-mangling-version=v0 -Crelocation-model=static -Zfunction-sections=n -Wclippy::float_arithmetic --target=./scripts/target.json -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2 -Zcf-protection=branch -Zno-jump-tables -Ctarget-cpu=x86-64 -Ztune-cpu=generic -Cno-redzone=y -Ccode-model=kernel -Zfunction-return=thunk-extern -Zpatchable-function-entry=16,16 -Copt-level=2 -Cdebug-assertions=n -Coverflow-checks=y -Dwarnings @./include/generated/rustc_cfg --edition=2021 --cfg no_fp_fmt_parse --emit=dep-info=rust/.core.o.d --emit=obj=rust/core.o --emit=metadata=rust/libcore.rmeta --crate-type rlib -L./rust --crate-name core /usr/lib/rust-1.84/lib/rustlib/src/rust/library/core/src/lib.rs --sysroot=/dev/null ;llvm-objcopy --redefine-sym __addsf3=__rust__addsf3 --redefine-sym __eqsf2=__rust__eqsf2 --redefine-sym __extendsfdf2=__rust__extendsfdf2 --redefine-sym __gesf2=__rust__gesf2 --redefine-sym __lesf2=__rust__lesf2 --redefine-sym __ltsf2=__rust__ltsf2 --redefine-sym __mulsf3=__rust__mulsf3 --redefine-sym __nesf2=__rust__nesf2 --redefine-sym __truncdfsf2=__rust__truncdfsf2 --redefine-sym __unordsf2=__rust__unordsf2 --redefine-sym __adddf3=__rust__adddf3 --redefine-sym __eqdf2=__rust__eqdf2 --redefine-sym __ledf2=__rust__ledf2 --redefine-sym __ltdf2=__rust__ltdf2 --redefine-sym __muldf3=__rust__muldf3 --redefine-sym __unorddf2=__rust__unorddf2 --redefine-sym __muloti4=__rust__muloti4 --redefine-sym __multi3=__rust__multi3 --redefine-sym __udivmodti4=__rust__udivmodti4 --redefine-sym __udivti3=__rust__udivti3 --redefine-sym __umodti3=__rust__umodti3 rust/core.o"""
-        expected = "/usr/lib/rust-1.84/lib/rustlib/src/rust/library/core/src/lib.rs rust/core.o"
-        self._assert_parsing(cmd, expected)
-
-    # rustdoc command tests
-    def test_rustdoc(self):
-        cmd = """OBJTREE=/workspace/linux/kernel_build rustdoc --test --edition=2021 -Zbinary_dep_depinfo=y -Astable_features -Dnon_ascii_idents -Dunsafe_op_in_unsafe_fn -Wmissing_docs -Wrust_2018_idioms -Wunreachable_pub -Wclippy::all -Wclippy::as_ptr_cast_mut -Wclippy::as_underscore -Wclippy::cast_lossless -Wclippy::ignored_unit_patterns -Wclippy::mut_mut -Wclippy::needless_bitwise_bool -Aclippy::needless_lifetimes -Wclippy::no_mangle_with_rust_abi -Wclippy::ptr_as_ptr -Wclippy::ptr_cast_constness -Wclippy::ref_as_ptr -Wclippy::undocumented_unsafe_blocks -Wclippy::unnecessary_safety_comment -Wclippy::unnecessary_safety_doc -Wrustdoc::missing_crate_level_docs -Wrustdoc::unescaped_backticks -Cpanic=abort -Cembed-bitcode=n -Clto=n -Cforce-unwind-tables=n -Ccodegen-units=1 -Csymbol-mangling-version=v0 -Crelocation-model=static -Zfunction-sections=n -Wclippy::float_arithmetic --target=aarch64-unknown-none -Ctarget-feature="-neon" -Cforce-unwind-tables=n -Zbranch-protection=pac-ret -Copt-level=2 -Cdebug-assertions=y -Coverflow-checks=y -Dwarnings -Cforce-frame-pointers=y -Zsanitizer=kernel-address -Zsanitizer-recover=kernel-address -Cllvm-args=-asan-mapping-offset=0xdfff800000000000 -Cpasses=sancov-module -Cllvm-args=-sanitizer-coverage-level=3 -Cllvm-args=-sanitizer-coverage-trace-pc -Cllvm-args=-sanitizer-coverage-trace-compares @./include/generated/rustc_cfg -L./rust --extern ffi --extern pin_init --extern kernel --extern build_error --extern macros --extern bindings --extern uapi --no-run --crate-name kernel -Zunstable-options --sysroot=/dev/null  --test-builder ./scripts/rustdoc_test_builder ../rust/kernel/lib.rs >/dev/null"""
-        expected = "../rust/kernel/lib.rs"
-        self._assert_parsing(cmd, expected)
-
-    def test_rustdoc_test_gen(self):
-        cmd = "./scripts/rustdoc_test_gen"
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # flex command tests
-    def test_flex(self):
-        cmd = "flex -oscripts/kconfig/lexer.lex.c -L ../scripts/kconfig/lexer.l"
-        expected = "../scripts/kconfig/lexer.l"
-        self._assert_parsing(cmd, expected)
-
-    # bison command tests
-    def test_bison(self):
-        cmd = "bison -o scripts/kconfig/parser.tab.c --defines=scripts/kconfig/parser.tab.h -t -l ../scripts/kconfig/parser.y"
-        expected = "../scripts/kconfig/parser.y"
-        self._assert_parsing(cmd, expected)
-
-    # bindgen command tests
-    def test_bindgen(self):
-        cmd = (
-            "bindgen ../rust/bindings/bindings_helper.h "
-            "--blocklist-type __kernel_s?size_t --blocklist-type __kernel_ptrdiff_t "
-            "--opaque-type xregs_state --opaque-type desc_struct --no-doc-comments "
-            "--rust-target 1.68 --use-core --with-derive-default -o rust/bindings/bindings_generated.rs "
-            "-- -Wp,-MMD,rust/bindings/.bindings_generated.rs.d -nostdinc -I../arch/x86/include "
-            "-include ../include/linux/compiler-version.h -D__KERNEL__ -fintegrated-as -fno-builtin -DMODULE; "
-            "sed -Ei 's/pub const RUST_CONST_HELPER_([a-zA-Z0-9_]*)/pub const \\1/g' rust/bindings/bindings_generated.rs"
-        )
-        expected = "../rust/bindings/bindings_helper.h ../include/linux/compiler-version.h"
-        self._assert_parsing(cmd, expected)
-
-    # perl command tests
-    def test_perl(self):
-        cmd = "perl ../lib/crypto/x86/poly1305-x86_64-cryptogams.pl > lib/crypto/x86/poly1305-x86_64-cryptogams.S"
-        expected = "../lib/crypto/x86/poly1305-x86_64-cryptogams.pl"
-        self._assert_parsing(cmd, expected)
-
-    # link-vmlinux.sh command tests
-    def test_link_vmlinux(self):
-        cmd = '../scripts/link-vmlinux.sh "ld" "-m elf_x86_64 -z noexecstack" "-z max-page-size=0x200000 --build-id=sha1 --orphan-handling=error --emit-relocs --discard-none" "vmlinux.unstripped";  true'
-        expected = "vmlinux.a"
-        self._assert_parsing(cmd, expected)
-
-    def test_link_vmlinux_postlink(self):
-        cmd = '../scripts/link-vmlinux.sh "ld" "-m elf_x86_64 -z noexecstack --no-warn-rwx-segments" "--emit-relocs --discard-none -z max-page-size=0x200000 --build-id=sha1 -X --orphan-handling=error";  make -f ../arch/x86/Makefile.postlink vmlinux'
-        expected = "vmlinux.a"
-        self._assert_parsing(cmd, expected)
-
-    # syscallhdr.sh command tests
-    def test_syscallhdr(self):
-        cmd = "sh ../scripts/syscallhdr.sh --abis common,64 --emit-nr   ../arch/x86/entry/syscalls/syscall_64.tbl arch/x86/include/generated/uapi/asm/unistd_64.h"
-        expected = "../arch/x86/entry/syscalls/syscall_64.tbl"
-        self._assert_parsing(cmd, expected)
-
-    # syscalltbl.sh command tests
-    def test_syscalltbl(self):
-        cmd = "sh ../scripts/syscalltbl.sh --abis common,64 ../arch/x86/entry/syscalls/syscall_64.tbl arch/x86/include/generated/asm/syscalls_64.h"
-        expected = "../arch/x86/entry/syscalls/syscall_64.tbl"
-        self._assert_parsing(cmd, expected)
-
-    # mkcapflags.sh command tests
-    def test_mkcapflags(self):
-        cmd = "sh ../arch/x86/kernel/cpu/mkcapflags.sh arch/x86/kernel/cpu/capflags.c ../arch/x86/kernel/cpu/../../include/asm/cpufeatures.h ../arch/x86/kernel/cpu/../../include/asm/vmxfeatures.h ../arch/x86/kernel/cpu/mkcapflags.sh FORCE"
-        expected = "../arch/x86/kernel/cpu/../../include/asm/cpufeatures.h ../arch/x86/kernel/cpu/../../include/asm/vmxfeatures.h"
-        self._assert_parsing(cmd, expected)
-
-    # orc_hash.sh command tests
-    def test_orc_hash(self):
-        cmd = "mkdir -p arch/x86/include/generated/asm/; sh ../scripts/orc_hash.sh < ../arch/x86/include/asm/orc_types.h > arch/x86/include/generated/asm/orc_hash.h"
-        expected = "../arch/x86/include/asm/orc_types.h"
-        self._assert_parsing(cmd, expected)
-
-    # xen-hypercalls.sh command tests
-    def test_xen_hypercalls(self):
-        cmd = "sh '../scripts/xen-hypercalls.sh' arch/x86/include/generated/asm/xen-hypercalls.h ../include/xen/interface/xen-mca.h ../include/xen/interface/xen.h ../include/xen/interface/xenpmu.h"
-        expected = "../include/xen/interface/xen-mca.h ../include/xen/interface/xen.h ../include/xen/interface/xenpmu.h"
-        self._assert_parsing(cmd, expected)
-
-    # gen_initramfs.sh command tests
-    def test_gen_initramfs(self):
-        cmd = "sh ../usr/gen_initramfs.sh -o usr/initramfs_data.cpio -l usr/.initramfs_data.cpio.d    ../usr/default_cpio_list"
-        expected = "../usr/default_cpio_list"
-        self._assert_parsing(cmd, expected)
-
-    # mkuboot.sh command tests
-    def test_mkuboot(self):
-        cmd = "bash ../scripts/mkuboot.sh -A arm -O linux -C none -T kernel -a 0x8000 -e 0x8000 -n 'Linux-6.15.0' -d arch/arm/boot/zImage arch/arm/boot/uImage"
-        expected = "arch/arm/boot/zImage"
-        self._assert_parsing(cmd, expected)
-
-    # syscallnr.sh command tests
-    def test_syscallnr(self):
-        cmd = "sh ../arch/arm/tools/syscallnr.sh ../arch/arm/tools/syscall.tbl arch/arm/include/generated/asm/unistd-nr.h"
-        expected = "../arch/arm/tools/syscall.tbl"
-        self._assert_parsing(cmd, expected)
-
-    # gen-kernel-hwcaps.sh command tests
-    def test_gen_kernel_hwcaps(self):
-        cmd = "/bin/sh -e ../arch/arm64/tools/gen-kernel-hwcaps.sh ../arch/arm64/include/uapi/asm/hwcap.h > arch/arm64/include/generated/asm/kernel-hwcap.h"
-        expected = "../arch/arm64/include/uapi/asm/hwcap.h"
-        self._assert_parsing(cmd, expected)
-
-    # vdso2c command tests
-    def test_vdso2c(self):
-        cmd = "arch/x86/entry/vdso/vdso2c arch/x86/entry/vdso/vdso64.so.dbg arch/x86/entry/vdso/vdso64.so arch/x86/entry/vdso/vdso-image-64.c"
-        expected = "arch/x86/entry/vdso/vdso64.so.dbg arch/x86/entry/vdso/vdso64.so"
-        self._assert_parsing(cmd, expected)
-
-    # vdsomunge command tests
-    def test_vdsomunge(self):
-        cmd = "arch/arm64/kernel/vdso32/../../../arm/vdso/vdsomunge arch/arm64/kernel/vdso32/vdso.so.raw arch/arm64/kernel/vdso32/vdso32.so.dbg"
-        expected = "arch/arm64/kernel/vdso32/vdso.so.raw"
-        self._assert_parsing(cmd, expected)
-
-    # mkpiggy command tests
-    def test_mkpiggy(self):
-        cmd = "arch/x86/boot/compressed/mkpiggy arch/x86/boot/compressed/vmlinux.bin.gz > arch/x86/boot/compressed/piggy.S"
-        expected = "arch/x86/boot/compressed/vmlinux.bin.gz"
-        self._assert_parsing(cmd, expected)
-
-    # relocs command tests
-    def test_relocs(self):
-        cmd = "arch/x86/tools/relocs vmlinux.unstripped > arch/x86/boot/compressed/vmlinux.relocs;arch/x86/tools/relocs --abs-relocs vmlinux.unstripped"
-        expected = "vmlinux.unstripped"
-        self._assert_parsing(cmd, expected)
-
-    def test_relocs_with_realmode(self):
-        cmd = (
-            "arch/x86/tools/relocs --realmode arch/x86/realmode/rm/realmode.elf > arch/x86/realmode/rm/realmode.relocs"
-        )
-        expected = "arch/x86/realmode/rm/realmode.elf"
-        self._assert_parsing(cmd, expected)
-
-    # mk_elfconfig command tests
-    def test_mk_elfconfig(self):
-        cmd = "scripts/mod/mk_elfconfig < scripts/mod/empty.o > scripts/mod/elfconfig.h"
-        expected = "scripts/mod/empty.o"
-        self._assert_parsing(cmd, expected)
-
-    # tools/build command tests
-    def test_build(self):
-        cmd = "arch/x86/boot/tools/build arch/x86/boot/setup.bin arch/x86/boot/vmlinux.bin arch/x86/boot/zoffset.h arch/x86/boot/bzImage"
-        expected = "arch/x86/boot/setup.bin arch/x86/boot/vmlinux.bin arch/x86/boot/zoffset.h"
-        self._assert_parsing(cmd, expected)
-
-    # extract-cert command tests
-    def test_extract_cert(self):
-        cmd = 'certs/extract-cert ""  certs/signing_key.x509'
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # dtc command tests
-    def test_dtc_cat(self):
-        cmd = "./scripts/dtc/dtc -o drivers/of/empty_root.dtb -b 0 -i../drivers/of/ -i../scripts/dtc/include-prefixes -Wno-unique_unit_address -Wno-unit_address_vs_reg -Wno-avoid_unnecessary_addr_size -Wno-alias_paths -Wno-graph_child_address -Wno-simple_bus_reg   -d drivers/of/.empty_root.dtb.d.dtc.tmp drivers/of/.empty_root.dtb.dts.tmp ; cat drivers/of/.empty_root.dtb.d.pre.tmp drivers/of/.empty_root.dtb.d.dtc.tmp > drivers/of/.empty_root.dtb.d"
-        expected = "drivers/of/.empty_root.dtb.dts.tmp drivers/of/.empty_root.dtb.d.pre.tmp drivers/of/.empty_root.dtb.d.dtc.tmp"
-        self._assert_parsing(cmd, expected)
-
-    # pnmtologo command tests
-    def test_pnmtologo(self):
-        cmd = "drivers/video/logo/pnmtologo -t clut224 -n logo_linux_clut224 -o drivers/video/logo/logo_linux_clut224.c ../drivers/video/logo/logo_linux_clut224.ppm"
-        expected = "../drivers/video/logo/logo_linux_clut224.ppm"
-        self._assert_parsing(cmd, expected)
-
-    # relacheck command tests
-    def test_relacheck(self):
-        cmd = "arch/arm64/kernel/pi/relacheck arch/arm64/kernel/pi/idreg-override.pi.o arch/arm64/kernel/pi/idreg-override.o"
-        expected = "arch/arm64/kernel/pi/idreg-override.pi.o"
-        self._assert_parsing(cmd, expected)
-
-    # gen-hyprel command tests
-    def test_gen_hyprel(self):
-        cmd = "arch/arm64/kvm/hyp/nvhe/gen-hyprel arch/arm64/kvm/hyp/nvhe/kvm_nvhe.tmp.o > arch/arm64/kvm/hyp/nvhe/hyp-reloc.S"
-        expected = "arch/arm64/kvm/hyp/nvhe/kvm_nvhe.tmp.o"
-        self._assert_parsing(cmd, expected)
-
-    # mkregtable command tests
-    def test_mkregtable(self):
-        cmd = "drivers/gpu/drm/radeon/mkregtable ../drivers/gpu/drm/radeon/reg_srcs/r100 > drivers/gpu/drm/radeon/r100_reg_safe.h"
-        expected = "../drivers/gpu/drm/radeon/reg_srcs/r100"
-        self._assert_parsing(cmd, expected)
-
-    # genheaders command tests
-    def test_genheaders(self):
-        cmd = "security/selinux/genheaders security/selinux/flask.h security/selinux/av_permissions.h"
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # mkcpustr command tests
-    def test_mkcpustr(self):
-        cmd = "arch/x86/boot/mkcpustr > arch/x86/boot/cpustr.h"
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # polgen command tests
-    def test_polgen(self):
-        cmd = "scripts/ipe/polgen/polgen security/ipe/boot_policy.c"
-        expected = ""
-        self._assert_parsing(cmd, expected)
-
-    # gen_header.py command tests
-    def test_gen_header(self):
-        cmd = "mkdir -p drivers/gpu/drm/msm/generated && python3 ../drivers/gpu/drm/msm/registers/gen_header.py --no-validate --rnn ../drivers/gpu/drm/msm/registers --xml ../drivers/gpu/drm/msm/registers/adreno/a2xx.xml c-defines > drivers/gpu/drm/msm/generated/a2xx.xml.h"
-        expected = "../drivers/gpu/drm/msm/registers/adreno/a2xx.xml"
-        self._assert_parsing(cmd, expected)
-
-
-if __name__ == "__main__":
-    unittest.main()
-- 
2.43.0


      parent reply	other threads:[~2026-10-12 21:34 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-12 21:33 [PATCH v3 0/7] kbuild: record cmd-prereqs in .cmd files Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 1/7] scripts/make_fit: limit .cmd file parsing to the savedcmd_ line Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 2/7] kbuild: refactor fixdep to collect dependencies before printing Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 3/7] scripts/sbom: skip make_prereqs lines when parsing .cmd files Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 4/7] kbuild: record cmd-prereqs in " Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 5/7] scripts/sbom: parse make_prereqs from " Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 6/7] scripts/sbom: use make_prereqs to determine build inputs Luis Augenstein
2026-10-12 21:33 ` Luis Augenstein [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261012213337.2466524-8-luis.augenstein@tngtech.com \
    --to=luis.augenstein@tngtech.com \
    --cc=akpm@linux-foundation.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=kstewart@linuxfoundation.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maximilian.huber@tngtech.com \
    --cc=nathan@kernel.org \
    --cc=nsc@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®