* [PATCH v3 6/7] scripts/sbom: use make_prereqs to determine build inputs
2026-10-12 21:33 [PATCH v3 0/7] kbuild: record cmd-prereqs in .cmd files Luis Augenstein
` (4 preceding siblings ...)
2026-10-12 21:33 ` [PATCH v3 5/7] scripts/sbom: parse make_prereqs from " Luis Augenstein
@ 2026-10-12 21:33 ` Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 7/7] scripts/sbom: remove the command-specific parsers Luis Augenstein
6 siblings, 0 replies; 8+ messages in thread
From: Luis Augenstein @ 2026-10-12 21:33 UTC (permalink / raw)
To: nathan, nsc
Cc: linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
maximilian.huber, Luis Augenstein
Build the list of file dependencies of a target from the
make_prereqs_<target> field and the deps_<target> entries of the .cmd
file instead of parsing the shell command stored in savedcmd_.
The prerequisites include more than KernelSbom wants to track: files
should be tracked if they end up in the kernel image or loadable
modules, but not each and every host tool or helper script used to
build them. Add a manually maintained exclude list for such
dependencies. It is still manual, but much easier to maintain than
the command-specific parsers that were needed to extract the relevant
inputs from each individual build command.
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>
---
scripts/sbom/sbom/cmd_graph/cmd_file.py | 46 ++-----------
.../sbom/sbom/cmd_graph/dependency_filter.py | 59 +++++++++++++++++
scripts/sbom/sbom/spdx_graph/kernel_file.py | 64 ++++++++++++-------
3 files changed, 105 insertions(+), 64 deletions(-)
create mode 100644 scripts/sbom/sbom/cmd_graph/dependency_filter.py
diff --git a/scripts/sbom/sbom/cmd_graph/cmd_file.py b/scripts/sbom/sbom/cmd_graph/cmd_file.py
index cc576c7c6be..ab4b00b252b 100644
--- a/scripts/sbom/sbom/cmd_graph/cmd_file.py
+++ b/scripts/sbom/sbom/cmd_graph/cmd_file.py
@@ -5,7 +5,7 @@ import os
import re
from dataclasses import dataclass, field
from sbom.cmd_graph.deps_parser import parse_cmd_file_deps
-from sbom.cmd_graph.savedcmd_parser import parse_inputs_from_commands
+from sbom.cmd_graph.dependency_filter import should_include_dependency
import sbom.sbom_logging as sbom_logging
from sbom.path_utils import PathStr
@@ -85,51 +85,17 @@ class CmdFile:
Returns:
list[PathStr]: dependency file paths relative to `obj_tree`.
"""
- input_files: list[PathStr] = [
- str(p) for p in parse_inputs_from_commands(self.savedcmd, fail_on_unknown_build_command)
- ]
+ input_files: list[PathStr] = list(self.make_prereqs)
+
if self.deps:
input_files += [str(p) for p in parse_cmd_file_deps(self.deps)]
- input_files = _expand_resolve_files(input_files, obj_tree)
cmd_file_dependencies: list[PathStr] = []
for input_file in input_files:
- # input files are either absolute or relative to the object tree
+ # input files are either absolute or already relative to the object tree
if os.path.isabs(input_file):
input_file = os.path.relpath(input_file, obj_tree)
- if input_file == target_path:
- # Skip target file to prevent cycles. This is necessary because some multi stage commands first create an output and then pass it as input to the next command, e.g., objcopy.
- continue
- cmd_file_dependencies.append(input_file)
+ if should_include_dependency(input_file):
+ cmd_file_dependencies.append(input_file)
unique_cmd_file_dependencies = list(dict.fromkeys(cmd_file_dependencies))
return unique_cmd_file_dependencies
-
-
-def _expand_resolve_files(input_files: list[PathStr], obj_tree: PathStr) -> list[PathStr]:
- """
- Expands resolve files which may reference additional files via '@' notation.
-
- Args:
- input_files (list[PathStr]): List of file paths relative to the object tree, where paths starting with '@' refer to files
- containing further file paths, each on a separate line.
- obj_tree: Absolute path to the root of the object tree.
-
- Returns:
- list[PathStr]: Flattened list of all input file paths, with any nested '@' file references resolved recursively.
- """
- expanded_input_files: list[PathStr] = []
- for input_file in input_files:
- if not input_file.startswith("@"):
- expanded_input_files.append(input_file)
- continue
- resolve_file_path = os.path.join(obj_tree, input_file.removeprefix("@"))
- if not os.path.exists(resolve_file_path):
- sbom_logging.error(
- "Skip resolving '{resolve_file_path}' because the response file does not exist.",
- resolve_file_path=resolve_file_path,
- )
- continue
- with open(resolve_file_path, "rt", encoding="utf-8") as f:
- resolve_file_content = [line_stripped for line in f.readlines() if (line_stripped := line.strip())]
- expanded_input_files += _expand_resolve_files(resolve_file_content, obj_tree)
- return expanded_input_files
diff --git a/scripts/sbom/sbom/cmd_graph/dependency_filter.py b/scripts/sbom/sbom/cmd_graph/dependency_filter.py
new file mode 100644
index 00000000000..f1fdc2cb965
--- /dev/null
+++ b/scripts/sbom/sbom/cmd_graph/dependency_filter.py
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0-only OR MIT
+# Copyright (C) 2025 TNG Technology Consulting GmbH
+
+import re
+
+from sbom.path_utils import PathStr
+
+# Regex patterns for dependencies that should not be tracked in the dependency graph.
+_COMPILED_EXCLUDE_PATTERNS: tuple[re.Pattern[str], ...] = (
+ # scripts in source tree (except module-common.c, which is compiled into every module)
+ re.compile(r"^\.\./scripts/(?!module-common\.c$)"),
+ # scripts and tools in obj tree
+ re.compile(r"^scripts/"),
+ re.compile(r"^tools/"),
+ re.compile(r"^arch/[^/]+/tools/"),
+ # Host helper scripts
+ re.compile(r".*\.sh$"),
+ re.compile(r".*\.py$"),
+ re.compile(r".*\.pl$"),
+ # Host-tool executables
+ re.compile(r"^certs/extract-cert$"),
+ re.compile(r"^security/selinux/genheaders$"),
+ re.compile(r"^usr/gen_init_cpio$"),
+ re.compile(r"^drivers/gpu/drm/radeon/mkregtable$"),
+ re.compile(r"^drivers/video/logo/pnmtologo$"),
+ re.compile(r"^lib/raid/raid6/mktables$"),
+ re.compile(r"^\.\./fs/smb/client/gen_smb1_mapping$"),
+ re.compile(r"^\.\./fs/smb/client/gen_smb2_mapping$"),
+ # Other
+ re.compile(r".*\.xsd$"),
+ re.compile(r".*purgatory\.chk$"),
+ re.compile(r".*\.genkey$"),
+ re.compile(r".*\.md$"),
+ re.compile(r"^include/config/"),
+ # x86
+ re.compile(r"^arch/x86/boot/compressed/mkpiggy$"),
+ re.compile(r"^arch/x86/boot/mkcpustr$"),
+ # arm
+ re.compile(r"^arch/arm/vdso/vdsomunge$"),
+ # arm64
+ re.compile(r"^arch/arm64/kvm/hyp/nvhe/gen-hyprel$"),
+ re.compile(r"^arch/arm64/kernel/pi/relacheck$"),
+)
+
+def should_include_dependency(path: PathStr) -> bool:
+ """
+ Return whether a `.cmd` dependency should appear in the tracked dependency graph.
+
+ Track files that are inputs to compiling or linking artifacts that end up in the
+ kernel image or loadable modules (e.g. source → object → archive → image/module).
+ Exclude host tools and helper scripts whose code is not linked into the kernel.
+
+ Args:
+ path: Dependency path relative to the object tree.
+
+ Returns:
+ True if the dependency should be included in the dependency graph.
+ """
+ return not any(pattern.match(path) for pattern in _COMPILED_EXCLUDE_PATTERNS)
diff --git a/scripts/sbom/sbom/spdx_graph/kernel_file.py b/scripts/sbom/sbom/spdx_graph/kernel_file.py
index 505f25f66eb..cea14cb3538 100644
--- a/scripts/sbom/sbom/spdx_graph/kernel_file.py
+++ b/scripts/sbom/sbom/spdx_graph/kernel_file.py
@@ -245,7 +245,7 @@ def _get_primary_purpose(absolute_path: PathStr) -> SoftwarePurpose | None:
return any(segment in absolute_path for segment in path_segments)
# Source code
- if ends_with([".c", ".h", ".S", ".s", ".rs", ".pl", "gen_smb1_mapping", "gen_smb2_mapping"]):
+ if ends_with([".c", ".h", ".S", ".s", ".rs"]):
return "source"
# Libraries
@@ -271,45 +271,61 @@ def _get_primary_purpose(absolute_path: PathStr) -> SoftwarePurpose | None:
# Data files
if ends_with(
[
- ".tbl",
- ".relocs",
- ".rmeta",
- ".in",
+ ".awk",
".dbg",
- ".x509",
- ".pbm",
- ".ppm",
".dtb",
- ".uc",
- ".inc",
+ ".dtbo",
".dts",
".dtsi",
- ".dtbo",
- ".xml",
+ ".dtso",
+ ".in",
+ ".inc",
+ ".json",
+ ".ld",
+ ".lds",
+ ".mod",
+ ".order",
+ ".pbm",
+ ".ppm",
+ ".relocs",
+ ".rmeta",
".ro",
- "initramfs_inc_data",
- "default_cpio_list",
- "x509_certificate_list",
- "utf8data.c_shipped",
+ ".tbl",
+ ".uc",
+ ".x509",
+ ".xml",
"blacklist_hash_list",
- "x509_revocation_list",
"cpucaps",
- "sysreg",
+ "default_cpio_list",
+ "initramfs_inc_data",
+ "kheaders.md5",
+ "kheaders-objlist",
+ "kheaders-srclist",
"mach-types",
+ "sysreg",
+ "utf8data.c_shipped",
+ "x509_certificate_list",
+ "x509_revocation_list",
]
) or includes_path_segments(["drivers/gpu/drm/radeon/reg_srcs/"]):
return "data"
# Configuration files
- if ends_with([".pem", ".key", ".conf", ".config", ".cfg", ".bconf"]):
+ if ends_with([
+ ".pem",
+ ".key",
+ ".conf",
+ ".config",
+ ".cfg",
+ ".bconf",
+ "config_data",
+ ".genkey",
+ "bindgen_parameters",
+ ]):
return "configuration"
- # Documentation
- if ends_with([".md"]):
- return "documentation"
-
# Other / miscellaneous
- if ends_with([".o", ".tmp"]):
+ if ends_with([".o"]):
return "other"
sbom_logging.warning("Could not infer primary purpose for {absolute_path}", absolute_path=absolute_path)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v3 7/7] scripts/sbom: remove the command-specific parsers
2026-10-12 21:33 [PATCH v3 0/7] kbuild: record cmd-prereqs in .cmd files Luis Augenstein
` (5 preceding siblings ...)
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
6 siblings, 0 replies; 8+ messages in thread
From: Luis Augenstein @ 2026-10-12 21:33 UTC (permalink / raw)
To: nathan, nsc
Cc: linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
maximilian.huber, Luis Augenstein
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
^ permalink raw reply [flat|nested] 8+ messages in thread