All of lore.kernel.org
 help / color / mirror / Atom feed
From: Omokefe Emmanuel Onanaroghene <emmaonana18@gmail.com>
To: mchehab+huawei@kernel.org
Cc: corbet@lwn.net, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, skhan@linuxfoundation.org,
	rdunlap@infradead.org, mchehab@kernel.org, paulmck@kernel.org,
	linusw@kernel.org, Julia.Lawall@inria.fr, gary@garyguo.net,
	rmk+kernel@armlinux.org.uk, hemanth.selam@gmail.com,
	Omokefe Emmanuel Onanaroghene <emmaonana18@gmail.com>
Subject: [PATCH v2 2/2] docs: kdoc: handle TRACE_EVENT_FN() with CMatch
Date: Fri, 23 Oct 2026 14:04:15 +0100	[thread overview]
Message-ID: <20261023130444.26270-3-emmaonana18@gmail.com> (raw)
In-Reply-To: <20261023130444.26270-1-emmaonana18@gmail.com>

kernel-doc fails to parse tracepoint declarations that use TRACE_EVENT_FN(), e.g. gpu_power_status:

  ... Unrecognized tracepoint format ...

  ... expecting prototype for gpu_power_status(). Prototype was for TRACE_EVENT_FN() instead

Convert SYSCALL_DEFINE0() through SYSCALL_DEFINE6(), the TRACE_EVENT() and DEFINE_EVENT() families,
DEFINE_SINGLE_EVENT(), and TP_PROTO() to CMatch transformations.
Add a CMatch back-reference form that trims whitespace around selected macro arguments,
and retain nested commas within arguments.

Add regression tests for TRACE_EVENT_FN() and SYSCALL_DEFINE0/3().

Signed-off-by: Omokefe Emmanuel Onanaroghene <emmaonana18@gmail.com>
---
 tools/lib/python/kdoc/c_lex.py        | 19 ++++++
 tools/lib/python/kdoc/kdoc_parser.py  | 94 ++-------------------------
 tools/lib/python/kdoc/xforms_lists.py | 39 +++++++++++
 tools/unittests/test_kdoc_parser.py   | 56 ++++++++++++++++
 4 files changed, 120 insertions(+), 88 deletions(-)

diff --git a/tools/lib/python/kdoc/c_lex.py b/tools/lib/python/kdoc/c_lex.py
index 532e2c5a815e..4adc1b211b54 100644
--- a/tools/lib/python/kdoc/c_lex.py
+++ b/tools/lib/python/kdoc/c_lex.py
@@ -338,6 +338,11 @@ class CTokenArgs:
 
             sub_str = KernRe(r'(\\\d+)[+]').sub(r"\1", sub_str)
 
+        self.trim_groups = set()
+        for match in KernRe(r'\\(\d+)-').finditer(sub_str):
+            self.trim_groups.add(int(match.group(1)))
+        sub_str = KernRe(r'(\\\d+)-').sub(r"\1", sub_str)
+
         self.sub_str = sub_str
         self.sub_tokeninzer = CTokenizer(sub_str)
 
@@ -448,8 +453,22 @@ class CTokenArgs:
         if pos < self.max_group:
             log.error(fr"{self.sub_str} groups are up to {pos} instead of {self.max_group}")
 
+        groups_list = [self._trim_group(group) if i in self.trim_groups else group
+                       for i, group in enumerate(groups_list)]
+
         return level, groups_list
 
+    @staticmethod
+    def _trim_group(tokens):
+        """Return macro argument tokens without surrounding whitespace."""
+        start = 0
+        end = len(tokens)
+        while start < end and tokens[start].kind == CToken.SPACE:
+            start += 1
+        while end > start and tokens[end - 1].kind == CToken.SPACE:
+            end -= 1
+        return tokens[start:end]
+
     def tokens(self, new_tokenizer):
         level, groups = self.groups(new_tokenizer)
 
diff --git a/tools/lib/python/kdoc/kdoc_parser.py b/tools/lib/python/kdoc/kdoc_parser.py
index 80d4245acd17..5057a131117b 100644
--- a/tools/lib/python/kdoc/kdoc_parser.py
+++ b/tools/lib/python/kdoc/kdoc_parser.py
@@ -1493,82 +1493,6 @@ class KernelDoc:
             self.entry.add_text(doc_content.group(1))
         # else ... ??
 
-    def syscall_munge(self, ln, proto):         # pylint: disable=W0613
-        """
-        Handle syscall definitions.
-        """
-
-        is_void = False
-
-        # Strip newlines/CR's
-        proto = re.sub(r'[\r\n]+', ' ', proto)
-
-        # Check if it's a SYSCALL_DEFINE0
-        if 'SYSCALL_DEFINE0' in proto:
-            is_void = True
-
-        # Replace SYSCALL_DEFINE with correct return type & function name
-        proto = KernRe(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
-
-        r = KernRe(r'long\s+(sys_.*?),')
-        if r.search(proto):
-            proto = KernRe(',').sub('(', proto, count=1)
-        elif is_void:
-            proto = KernRe(r'\)').sub('(void)', proto, count=1)
-
-        # Now delete all of the odd-numbered commas in the proto
-        # so that argument types & names don't have a comma between them
-        count = 0
-        length = len(proto)
-
-        if is_void:
-            length = 0  # skip the loop if is_void
-
-        for ix in range(length):
-            if proto[ix] == ',':
-                count += 1
-                if count % 2 == 1:
-                    proto = proto[:ix] + ' ' + proto[ix + 1:]
-
-        return proto
-
-    def tracepoint_munge(self, ln, proto):
-        """
-        Handle tracepoint definitions.
-        """
-
-        tracepointname = None
-        tracepointargs = None
-
-        # Match tracepoint name based on different patterns
-        r = KernRe(r'TRACE_EVENT\((.*?),')
-        if r.search(proto):
-            tracepointname = r.group(1)
-
-        r = KernRe(r'DEFINE_SINGLE_EVENT\((.*?),')
-        if r.search(proto):
-            tracepointname = r.group(1)
-
-        r = KernRe(r'DEFINE_EVENT\((.*?),(.*?),')
-        if r.search(proto):
-            tracepointname = r.group(2)
-
-        if tracepointname:
-            tracepointname = tracepointname.lstrip()
-
-        r = KernRe(r'TP_PROTO\((.*?)\)')
-        if r.search(proto):
-            tracepointargs = r.group(1)
-
-        if not tracepointname or not tracepointargs:
-            self.emit_msg(ln,
-                          f"Unrecognized tracepoint format:\n{proto}\n")
-        else:
-            proto = f"static inline void trace_{tracepointname}({tracepointargs})"
-            self.entry.identifier = f"trace_{self.entry.identifier}"
-
-        return proto
-
     def process_proto_function(self, ln, line, source):
         """Ancillary routine to process a function prototype."""
 
@@ -1597,18 +1521,12 @@ class KernelDoc:
             #
             r = KernRe(r'^(\S+\s+)\(\s*\*(\S+)\)')
             self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
-            #
-            # Handle special declaration syntaxes
-            #
-            if 'SYSCALL_DEFINE' in self.entry.prototype:
-                self.entry.prototype = self.syscall_munge(ln,
-                                                          self.entry.prototype)
-            else:
-                r = KernRe(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
-                if r.search(self.entry.prototype):
-                    self.entry.prototype = self.tracepoint_munge(ln,
-                                                                 self.entry.prototype)
-            #
+            # Tracepoint documentation uses the short event name, while its
+            # generated function has the trace_ prefix. The declaration itself
+            # is normalized by CTransforms in dump_function().
+            if self.xforms.is_tracepoint(self.entry.prototype):
+                self.entry.identifier = f"trace_{self.entry.identifier}"
+
             # ... and we're done
             #
             self.dump_function(ln, self.entry.prototype, source)
diff --git a/tools/lib/python/kdoc/xforms_lists.py b/tools/lib/python/kdoc/xforms_lists.py
index 15f6f21c7a9e..315b54feff33 100644
--- a/tools/lib/python/kdoc/xforms_lists.py
+++ b/tools/lib/python/kdoc/xforms_lists.py
@@ -17,6 +17,13 @@ class CTransforms:
     into something we can parse and generate kdoc for.
     """
 
+    tracepoint_pattern = (
+        r"(?:TRACE_EVENT(?:_FN(?:_COND)?|_CONDITION|_SYSCALL)?|"
+        r"DEFINE_EVENT(?:_FN|_PRINT|_CONDITION|_NOP|_WRITABLE)?|"
+        r"DEFINE_SINGLE_EVENT)"
+    )
+    tracepoint_match = CMatch(tracepoint_pattern)
+
     #
     # NOTE:
     #      Due to performance reasons, place CMatch rules before KernRe,
@@ -108,6 +115,32 @@ class CTransforms:
         (CMatch("STATIC_IFN_KUNIT"), ""),
         (CMatch("INLINE_IFN_KUNIT"), ""),
 
+        # Turn syscall declaration macros into ordinary function prototypes.
+        (CMatch("SYSCALL_DEFINE0"), r"long sys_\1( void )"),
+        (CMatch("SYSCALL_DEFINE1"), r"long sys_\1(\2- \3-)"),
+        (CMatch("SYSCALL_DEFINE2"), r"long sys_\1(\2- \3-, \4- \5-)"),
+        (CMatch("SYSCALL_DEFINE3"),
+         r"long sys_\1(\2- \3-, \4- \5-, \6- \7-)"),
+        (CMatch("SYSCALL_DEFINE4"),
+         r"long sys_\1(\2- \3-, \4- \5-, \6- \7-, \8- \9-)"),
+        (CMatch("SYSCALL_DEFINE5"),
+         r"long sys_\1(\2- \3-, \4- \5-, \6- \7-, \8- \9-, "
+         r"\10- \11-)"),
+        (CMatch("SYSCALL_DEFINE6"),
+         r"long sys_\1(\2- \3-, \4- \5-, \6- \7-, \8- \9-, "
+         r"\10- \11-, \12- \13-)"),
+
+        # Tracepoint documentation uses the event name, while the generated
+        # function has the trace_ prefix. The proto argument is unwrapped
+        # separately below.
+        (CMatch(r"TRACE_EVENT(?:_FN(?:_COND)?|_CONDITION|_SYSCALL)?"),
+         r"static inline void trace_\1-(\2-)"),
+        (CMatch(r"DEFINE_EVENT(?:_FN|_PRINT|_CONDITION|_NOP|_WRITABLE)?"),
+         r"static inline void trace_\2-(\3-)"),
+        (CMatch("DEFINE_SINGLE_EVENT"),
+         r"static inline void trace_\1-(\2-)"),
+        (CMatch("TP_PROTO"), r"\0"),
+
         #
         # HACK: this is similar to process_export() hack. It is meant to
         # drop _noproof from function name. See for instance:
@@ -159,3 +192,9 @@ class CTransforms:
 
             source = search.sub(subst, source)
         return str(source)
+
+    @classmethod
+    def is_tracepoint(cls, source):
+        """Return whether source starts with a supported tracepoint macro."""
+
+        return any(cls.tracepoint_match.search(source))
diff --git a/tools/unittests/test_kdoc_parser.py b/tools/unittests/test_kdoc_parser.py
index 4baa78ca02b3..1702f912c897 100755
--- a/tools/unittests/test_kdoc_parser.py
+++ b/tools/unittests/test_kdoc_parser.py
@@ -444,6 +444,62 @@ class TestContextLockStruct(GenerateKdocItem):
         self.assertEqual(entries[0].name, "debugfs_cancellation")
         self.assertEqual(entries[0].warnings, [])
 
+
+class TestSpecialFunctionMacros(GenerateKdocItem):
+    def _parse(self, source):
+        kernel_doc = KernelDoc(self.config, "test.c", self.xforms)
+        patcher = patch('builtins.open', new_callable=mock_open,
+                        read_data=dedent(source))
+        with patcher:
+            return kernel_doc.parse_kdoc()[1]
+
+    def test_trace_event_fn(self):
+        entries = self._parse("""
+            /**
+             * gpu_power_status - called when hardware turns on or off
+             * @dev: pointer to device
+             * @shader_bitmap: bitmap
+             *
+             * Description of the tracepoint.
+             */
+            TRACE_EVENT_FN(gpu_power_status, TP_PROTO(const struct device *dev, u64 shader_bitmap), TP_ARGS(dev, shader_bitmap), TP_STRUCT__entry(__field(u64, shader_bitmap)), TP_fast_assign(__entry->shader_bitmap = shader_bitmap;), TP_printk("%s", __get_str(dev_name)), my_register, my_unregister);
+        """)
+
+        self.assertEqual(len(entries), 1)
+        self.assertEqual(entries[0].name, "trace_gpu_power_status")
+        self.assertEqual(entries[0].warnings, [])
+
+    def test_syscall_define_zero(self):
+        entries = self._parse("""
+            /**
+             * sys_demo - demo syscall
+             *
+             * Return: zero
+             */
+            SYSCALL_DEFINE0(demo);
+        """)
+
+        self.assertEqual(len(entries), 1)
+        self.assertEqual(entries[0].name, "sys_demo")
+        self.assertEqual(entries[0].warnings, [])
+
+    def test_syscall_define_three(self):
+        entries = self._parse("""
+            /**
+             * sys_demo - demo syscall
+             * @one: first value
+             * @two: second value
+             * @three: third value
+             *
+             * Return: zero
+             */
+            SYSCALL_DEFINE3(demo, int, one, long, two, unsigned int, three);
+        """)
+
+        self.assertEqual(len(entries), 1)
+        self.assertEqual(entries[0].name, "sys_demo")
+        self.assertEqual(entries[0].warnings, [])
+
 #
 # Class and logic to create dynamic tests from YAML
 #
-- 
2.43.0


  parent reply	other threads:[~2026-10-23 13:06 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-02  4:15 [PATCH] docs: kdoc: strip DOMAIN_NS() wrapper in function prototypes Omokefe Emmanuel Onanaroghene
2026-10-02  4:28 ` Randy Dunlap
2026-10-14 17:22 ` Jonathan Corbet
2026-10-14 22:47   ` Omokefe Emmanuel Onanaroghene
2026-10-15  0:53     ` Omokefe Emmanuel Onanaroghene
2026-10-15 13:00       ` Jonathan Corbet
2026-10-15 16:44         ` [PATCH v3 0/2] docs: kdoc: fix TRACE_EVENT_FN and DOMAIN_NS parsing Omokefe Emmanuel Onanaroghene
2026-10-15 16:44           ` [PATCH v3 1/2] docs: kdoc: handle TRACE_EVENT_FN() family in tracepoint parser Omokefe Emmanuel Onanaroghene
2026-10-15 17:06             ` Mauro Carvalho Chehab
2026-10-16 20:43               ` [PATCH] " Omokefe Emmanuel Onanaroghene
2026-10-16 21:11                 ` Mauro Carvalho Chehab
2026-10-23 13:04                   ` [PATCH v2 0/2] docs: kdoc: convert tracepoint parsing to CMatch Omokefe Emmanuel Onanaroghene
2026-10-23 13:04                     ` [PATCH v2 1/2] docs: kdoc: handle nested commas in CMatch arguments Omokefe Emmanuel Onanaroghene
2026-10-23 13:04                     ` Omokefe Emmanuel Onanaroghene [this message]
2026-10-15 16:44           ` [PATCH v3 2/2] docs: kdoc: strip DOMAIN_NS() wrapper in function prototypes Omokefe Emmanuel Onanaroghene

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=20261023130444.26270-3-emmaonana18@gmail.com \
    --to=emmaonana18@gmail.com \
    --cc=Julia.Lawall@inria.fr \
    --cc=corbet@lwn.net \
    --cc=gary@garyguo.net \
    --cc=hemanth.selam@gmail.com \
    --cc=linusw@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mchehab+huawei@kernel.org \
    --cc=mchehab@kernel.org \
    --cc=paulmck@kernel.org \
    --cc=rdunlap@infradead.org \
    --cc=rmk+kernel@armlinux.org.uk \
    --cc=skhan@linuxfoundation.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.