public inbox for linux-kbuild@vger.kernel.org
 help / color / mirror / Atom feed
From: Luis <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 v5 06/15] scripts/sbom: add additional dependency sources for cmd graph
Date: Fri, 10 Apr 2026 23:22:46 +0200	[thread overview]
Message-ID: <20260410212255.9883-7-luis.augenstein@tngtech.com> (raw)
In-Reply-To: <20260410212255.9883-1-luis.augenstein@tngtech.com>

From: Luis Augenstein <luis.augenstein@tngtech.com>

Add hardcoded dependencies and .incbin directive parsing to
discover dependencies not tracked by .cmd files.

Assisted-by: Cursor:claude-sonnet-4-5
Assisted-by: OpenCode:GLM-4-7
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_graph_node.py | 33 +++++++-
 .../sbom/cmd_graph/hardcoded_dependencies.py  | 83 +++++++++++++++++++
 scripts/sbom/sbom/cmd_graph/incbin_parser.py  | 42 ++++++++++
 3 files changed, 157 insertions(+), 1 deletion(-)
 create mode 100644 scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py
 create mode 100644 scripts/sbom/sbom/cmd_graph/incbin_parser.py

diff --git a/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py b/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py
index 7a5279a1ba0..feacdbf7695 100644
--- a/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py
+++ b/scripts/sbom/sbom/cmd_graph/cmd_graph_node.py
@@ -2,15 +2,24 @@
 # Copyright (C) 2025 TNG Technology Consulting GmbH
 
 from dataclasses import dataclass, field
+from itertools import chain
 import logging
 import os
 from typing import Iterator, Protocol
 
 from sbom import sbom_logging
 from sbom.cmd_graph.cmd_file import CmdFile
+from sbom.cmd_graph.hardcoded_dependencies import get_hardcoded_dependencies
+from sbom.cmd_graph.incbin_parser import parse_incbin_statements
 from sbom.path_utils import PathStr, is_relative_to
 
 
+@dataclass
+class IncbinDependency:
+    node: "CmdGraphNode"
+    full_statement: str
+
+
 class CmdGraphNodeConfig(Protocol):
     obj_tree: PathStr
     src_tree: PathStr
@@ -28,11 +37,17 @@ class CmdGraphNode:
     """Parsed .cmd file describing how the file at absolute_path was built, or None if not available."""
 
     cmd_file_dependencies: list["CmdGraphNode"] = field(default_factory=list["CmdGraphNode"])
+    incbin_dependencies: list[IncbinDependency] = field(default_factory=list[IncbinDependency])
+    hardcoded_dependencies: list["CmdGraphNode"] = field(default_factory=list["CmdGraphNode"])
 
     @property
     def children(self) -> Iterator["CmdGraphNode"]:
         seen: set[PathStr] = set()
-        for node in self.cmd_file_dependencies:
+        for node in chain(
+            self.cmd_file_dependencies,
+            (dep.node for dep in self.incbin_dependencies),
+            self.hardcoded_dependencies,
+        ):
             if node.absolute_path not in seen:
                 seen.add(node.absolute_path)
                 yield node
@@ -95,6 +110,13 @@ class CmdGraphNode:
         def _build_child_node(child_path: PathStr) -> "CmdGraphNode":
             return CmdGraphNode.create(child_path, config, cache, depth + 1)
 
+        node.hardcoded_dependencies = [
+            _build_child_node(hardcoded_dependency_path)
+            for hardcoded_dependency_path in get_hardcoded_dependencies(
+                target_path_absolute, config.obj_tree, config.src_tree
+            )
+        ]
+
         if cmd_file is not None:
             node.cmd_file_dependencies = [
                 _build_child_node(cmd_file_dependency_path)
@@ -103,6 +125,15 @@ class CmdGraphNode:
                 )
             ]
 
+        if node.absolute_path.endswith(".S"):
+            node.incbin_dependencies = [
+                IncbinDependency(
+                    node=_build_child_node(incbin_statement.path),
+                    full_statement=incbin_statement.full_statement,
+                )
+                for incbin_statement in parse_incbin_statements(node.absolute_path)
+            ]
+
         return node
 
 
diff --git a/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py b/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py
new file mode 100644
index 00000000000..a5977f14ae4
--- /dev/null
+++ b/scripts/sbom/sbom/cmd_graph/hardcoded_dependencies.py
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0-only OR MIT
+# Copyright (C) 2025 TNG Technology Consulting GmbH
+
+import os
+from typing import Callable
+import sbom.sbom_logging as sbom_logging
+from sbom.path_utils import PathStr, is_relative_to
+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"],
+}
+
+
+def get_hardcoded_dependencies(path: PathStr, obj_tree: PathStr, src_tree: PathStr) -> list[PathStr]:
+    """
+    Some files in the kernel build process are not tracked by the .cmd dependency mechanism.
+    Parsing these dependencies programmatically is too complex for the scope of this project.
+    Therefore, this function provides manually defined dependencies to be added to the build graph.
+
+    Args:
+        path: absolute path to a file within the src tree or object tree.
+        obj_tree: absolute Path to the base directory of the object tree.
+        src_tree: absolute Path to the `linux` source directory.
+
+    Returns:
+        list[PathStr]: A list of dependency file paths (relative to the object tree) required to build the file at the given path.
+    """
+    if is_relative_to(path, obj_tree):
+        path = os.path.relpath(path, obj_tree)
+    elif is_relative_to(path, src_tree):
+        path = os.path.relpath(path, src_tree)
+
+    if path not in HARDCODED_DEPENDENCIES:
+        return []
+
+    template_variables: dict[str, Callable[[], str | None]] = {
+        "arch": lambda: _get_arch(path),
+    }
+
+    dependencies: list[PathStr] = []
+    for dependency_template in HARDCODED_DEPENDENCIES[path]:
+        dependency = _evaluate_template(dependency_template, template_variables)
+        if dependency is None:
+            continue
+        if os.path.exists(os.path.join(obj_tree, dependency)):
+            dependencies.append(dependency)
+        elif os.path.exists(os.path.join(src_tree, dependency)):
+            dependencies.append(os.path.relpath(dependency, obj_tree))
+        else:
+            sbom_logging.error(
+                "Skip hardcoded dependency '{dependency}' for '{path}' because the dependency lies neither in the src tree nor the object tree.",
+                dependency=dependency,
+                path=path,
+            )
+
+    return dependencies
+
+
+def _evaluate_template(template: str, variables: dict[str, Callable[[], str | None]]) -> str | None:
+    for key, value_function in variables.items():
+        template_key = "{" + key + "}"
+        if template_key in template:
+            value = value_function()
+            if value is None:
+                return None
+            template = template.replace(template_key, value)
+    return template
+
+
+def _get_arch(path: PathStr):
+    srcarch = Environment.SRCARCH()
+    if srcarch is None:
+        sbom_logging.error(
+            "Skipped architecture specific hardcoded dependency for '{path}' because the SRCARCH environment variable was not set.",
+            path=path,
+        )
+        return None
+    return srcarch
diff --git a/scripts/sbom/sbom/cmd_graph/incbin_parser.py b/scripts/sbom/sbom/cmd_graph/incbin_parser.py
new file mode 100644
index 00000000000..130f9520837
--- /dev/null
+++ b/scripts/sbom/sbom/cmd_graph/incbin_parser.py
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-only OR MIT
+# Copyright (C) 2025 TNG Technology Consulting GmbH
+
+from dataclasses import dataclass
+import re
+
+from sbom.path_utils import PathStr
+
+INCBIN_PATTERN = re.compile(r'\s*\.incbin\s+"(?P<path>[^"]+)"')
+"""Regex pattern for matching `.incbin "<path>"` statements."""
+
+
+@dataclass
+class IncbinStatement:
+    """A parsed `.incbin "<path>"` directive."""
+
+    path: PathStr
+    """path to the file referenced by the `.incbin` directive."""
+
+    full_statement: str
+    """Full `.incbin "<path>"` statement as it originally appeared in the file."""
+
+
+def parse_incbin_statements(absolute_path: PathStr) -> list[IncbinStatement]:
+    """
+    Parses `.incbin` directives from an `.S` assembly file.
+
+    Args:
+        absolute_path: Absolute path to the `.S` assembly file.
+
+    Returns:
+        list[IncbinStatement]: Parsed `.incbin` statements.
+    """
+    with open(absolute_path, "rt") as f:
+        content = f.read()
+    return [
+        IncbinStatement(
+            path=match.group("path"),
+            full_statement=match.group(0).strip(),
+        )
+        for match in INCBIN_PATTERN.finditer(content)
+    ]
-- 
2.43.0


  parent reply	other threads:[~2026-04-10 21:23 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-10 21:22 [PATCH v5 00/15] add SPDX SBOM generation script Luis
2026-04-10 21:22 ` [PATCH v5 01/15] scripts/sbom: add documentation Luis
2026-04-10 21:22 ` [PATCH v5 02/15] scripts/sbom: integrate script in make process Luis
2026-04-10 21:22 ` [PATCH v5 03/15] scripts/sbom: setup sbom logging Luis
2026-04-10 21:22 ` [PATCH v5 04/15] scripts/sbom: add command parsers Luis
2026-04-10 21:22 ` [PATCH v5 05/15] scripts/sbom: add cmd graph generation Luis
2026-04-10 21:22 ` Luis [this message]
2026-04-10 21:22 ` [PATCH v5 07/15] scripts/sbom: add SPDX classes Luis
2026-04-10 21:22 ` [PATCH v5 08/15] scripts/sbom: add JSON-LD serialization Luis
2026-04-10 21:22 ` [PATCH v5 09/15] scripts/sbom: add shared SPDX elements Luis
2026-04-10 21:22 ` [PATCH v5 10/15] scripts/sbom: collect file metadata Luis
2026-04-10 21:22 ` [PATCH v5 11/15] scripts/sbom: add SPDX output graph Luis
2026-04-10 21:22 ` [PATCH v5 12/15] scripts/sbom: add SPDX source graph Luis
2026-04-10 21:22 ` [PATCH v5 13/15] scripts/sbom: add SPDX build graph Luis
2026-04-10 21:22 ` [PATCH v5 14/15] scripts/sbom: add unit tests for command parsers Luis
2026-04-10 21:22 ` [PATCH v5 15/15] scripts/sbom: add unit tests for SPDX-License-Identifier parsing Luis

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=20260410212255.9883-7-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