This is an automated email from the ASF dual-hosted git repository.

michallenc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit c0238938105420d26a3ae2bcf55e21461d2fc1df
Author: mazhuang <[email protected]>
AuthorDate: Mon Nov 2 19:03:01 2026 +0800

    drivers/rpmsg: record the received messages in the note stream
    
    Add rpmsg_trace() and rpmsg_vtrace(), which write a formatted record
    and, optionally, a copy of the message to the note stream under the new
    NOTE_TAG_RPMSG tag. The note drivers then keep the last messages that
    went through an rpmsg transport, which helps to find out what a peer
    sent before a hang or a crash.
    
    The text is written with sched_note_vprintf() and the payload as a
    NOTE_DUMP_BINARY event; a spinlock keeps the two records of one call
    together when several CPUs trace at the same time.
    CONFIG_RPMSG_TRACE_BACKTRACE appends a backtrace of the caller to the
    records that ask for one.
    
    rpmsg_port traces the start and the end of every endpoint callback.
    
    Signed-off-by: yangao1 <[email protected]>
    Signed-off-by: mazhuang <[email protected]>
    Signed-off-by: Bowen Wang <[email protected]>
---
 drivers/rpmsg/CMakeLists.txt |   4 ++
 drivers/rpmsg/Kconfig        |  18 ++++++
 drivers/rpmsg/Make.defs      |   4 ++
 drivers/rpmsg/rpmsg_port.c   |  12 ++++
 drivers/rpmsg/rpmsg_trace.c  | 146 +++++++++++++++++++++++++++++++++++++++++++
 include/nuttx/rpmsg/rpmsg.h  |  27 ++++++++
 include/nuttx/sched_note.h   |   1 +
 7 files changed, 212 insertions(+)

diff --git a/drivers/rpmsg/CMakeLists.txt b/drivers/rpmsg/CMakeLists.txt
index 8cfb58d5b44..cc79e76393b 100644
--- a/drivers/rpmsg/CMakeLists.txt
+++ b/drivers/rpmsg/CMakeLists.txt
@@ -25,6 +25,10 @@ if(CONFIG_RPMSG)
 
   list(APPEND SRCS rpmsg.c)
 
+  if(CONFIG_RPMSG_TRACE)
+    list(APPEND SRCS rpmsg_trace.c)
+  endif()
+
   if(CONFIG_RPMSG_PING)
     list(APPEND SRCS rpmsg_ping.c)
   endif()
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 2939850e1af..78a038b1f7b 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -10,6 +10,24 @@ config RPMSG
 
 if RPMSG
 
+config RPMSG_TRACE
+       bool "rpmsg trace"
+       default n
+       depends on SCHED_INSTRUMENTATION_DUMP
+       ---help---
+               Record the messages passed through the rpmsg transports in the
+               note stream under NOTE_TAG_RPMSG, so they can be read back with
+               the note drivers (e.g. /dev/note/ram).
+
+config RPMSG_TRACE_BACKTRACE
+       int "rpmsg trace backtrace depth"
+       default 0
+       range 0 16
+       depends on RPMSG_TRACE
+       ---help---
+               Number of frames recorded with a trace that asks for a
+               backtrace. 0 disables backtraces.
+
 config RPMSG_LOCAL_CPUNAME
        string "Rpmsg Local Cpuname"
        default LIBC_HOSTNAME
diff --git a/drivers/rpmsg/Make.defs b/drivers/rpmsg/Make.defs
index 5ac4247cb8b..cc43f7834be 100644
--- a/drivers/rpmsg/Make.defs
+++ b/drivers/rpmsg/Make.defs
@@ -26,6 +26,10 @@ ifeq ($(CONFIG_RPMSG),y)
 
 CSRCS += rpmsg.c
 
+ifeq ($(CONFIG_RPMSG_TRACE),y)
+CSRCS += rpmsg_trace.c
+endif
+
 ifeq ($(CONFIG_RPMSG_PING),y)
 CSRCS += rpmsg_ping.c
 endif
diff --git a/drivers/rpmsg/rpmsg_port.c b/drivers/rpmsg/rpmsg_port.c
index 62cacf033d0..025696840dc 100644
--- a/drivers/rpmsg/rpmsg_port.c
+++ b/drivers/rpmsg/rpmsg_port.c
@@ -439,6 +439,7 @@ static void rpmsg_port_rx_callback(FAR struct rpmsg_port_s 
*port,
   FAR struct rpmsg_hdr *rphdr = (FAR struct rpmsg_hdr *)hdr->buf;
   FAR void *data = RPMSG_LOCATE_DATA(rphdr);
   FAR struct rpmsg_endpoint *ept;
+  size_t len = rphdr->len + sizeof(*rphdr);
   int status = 0;
 
   metal_mutex_acquire(&rdev->lock);
@@ -454,7 +455,18 @@ static void rpmsg_port_rx_callback(FAR struct rpmsg_port_s 
*port,
           ept->dest_addr = rphdr->src;
         }
 
+      rpmsg_trace(ept->name, false, rphdr, len,
+                  "[Port] rx ept->cb start ept:%p name:%s cb:%p "
+                  "rdev:%p hdr:%p len:%zu\n",
+                  ept, ept->name, ept->cb, rdev, rphdr, len);
+
       status = ept->cb(ept, data, rphdr->len, rphdr->src, ept->priv);
+
+      rpmsg_trace(ept->name, false, NULL, 0,
+                  "[Port] rx ept->cb end ept:%p name:%s cb:%p "
+                  "rdev:%p hdr:%p len:%zu\n",
+                  ept, ept->name, ept->cb, rdev, rphdr, len);
+
       if (status < 0 && status != RPMSG_SUCCESS_BUFFER_RELEASED)
         {
           RPMSG_ASSERT(0, "unexpected callback status\n");
diff --git a/drivers/rpmsg/rpmsg_trace.c b/drivers/rpmsg/rpmsg_trace.c
new file mode 100644
index 00000000000..f5e52a9fbbf
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_trace.c
@@ -0,0 +1,146 @@
+/****************************************************************************
+ * drivers/rpmsg/rpmsg_trace.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <execinfo.h>
+
+#include <nuttx/sched_note.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/streams.h>
+#include <nuttx/rpmsg/rpmsg.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* nc_length is a uint8_t, so a payload has to be split into notes that
+ * each fit in it.
+ */
+
+#define RPMSG_TRACE_CHUNK (UINT8_MAX - SIZEOF_NOTE_EVENT(0))
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Keeps a text record and its binary payload next to each other in the
+ * note stream when several CPUs trace at the same time.
+ */
+
+static spinlock_t g_rpmsg_trace_lock = SP_UNLOCKED;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsg_trace
+ ****************************************************************************/
+
+void rpmsg_trace(FAR const char *name, bool bt, FAR const void *buf,
+                 size_t len, FAR const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  rpmsg_vtrace(name, bt, buf, len, format, ap);
+  va_end(ap);
+}
+
+/****************************************************************************
+ * Name: rpmsg_vtrace
+ ****************************************************************************/
+
+void rpmsg_vtrace(FAR const char *name, bool bt, FAR const void *buf,
+                  size_t len, FAR const char *format, va_list ap)
+{
+  irqstate_t flags;
+
+  UNUSED(name);
+
+#if CONFIG_RPMSG_TRACE_BACKTRACE > 0
+  if (bt)
+    {
+      FAR void *frames[CONFIG_RPMSG_TRACE_BACKTRACE];
+      char btbuf[BACKTRACE_BUFFER_SIZE(CONFIG_RPMSG_TRACE_BACKTRACE)];
+      char line[256];
+      va_list copy;
+      int n;
+
+      /* The note driver keeps the raw arguments and formats them later,
+       * so the message must already be a string. 256 bytes is the size
+       * of one note printf record.
+       */
+
+      va_copy(copy, ap);
+      n = vsnprintf(line, sizeof(line), format, copy);
+      va_end(copy);
+
+      n = MIN(MAX(n, 0), (int)sizeof(line) - 1);
+      if (n > 0 && line[n - 1] == '\n')
+        {
+          n--;
+        }
+
+      backtrace(frames, CONFIG_RPMSG_TRACE_BACKTRACE);
+      backtrace_format(btbuf, sizeof(btbuf), frames,
+                       CONFIG_RPMSG_TRACE_BACKTRACE);
+      snprintf(line + n, sizeof(line) - n, ", %s", btbuf);
+      flags = spin_lock_irqsave(&g_rpmsg_trace_lock);
+      sched_note_printf(NOTE_TAG_RPMSG, "%s", line);
+    }
+  else
+#endif
+    {
+      va_list copy;
+
+      /* va_list is an array on some ABIs, so &ap of a parameter is not a
+       * va_list *; take a local copy.
+       */
+
+      va_copy(copy, ap);
+      flags = spin_lock_irqsave(&g_rpmsg_trace_lock);
+      sched_note_vprintf(NOTE_TAG_RPMSG, format, copy);
+      va_end(copy);
+    }
+
+  while (buf != NULL && len > 0)
+    {
+      size_t chunk = MIN(len, RPMSG_TRACE_CHUNK);
+
+      sched_note_event(NOTE_TAG_RPMSG, NOTE_DUMP_BINARY, buf, chunk);
+      buf = (FAR const uint8_t *)buf + chunk;
+      len -= chunk;
+    }
+
+  spin_unlock_irqrestore(&g_rpmsg_trace_lock, flags);
+}
diff --git a/include/nuttx/rpmsg/rpmsg.h b/include/nuttx/rpmsg/rpmsg.h
index 6aa96baccc3..72fe42f7ae4 100644
--- a/include/nuttx/rpmsg/rpmsg.h
+++ b/include/nuttx/rpmsg/rpmsg.h
@@ -29,6 +29,7 @@
 
 #include <nuttx/config.h>
 #include <nuttx/atomic.h>
+#include <nuttx/compiler.h>
 
 #ifdef CONFIG_RPMSG
 
@@ -116,6 +117,32 @@ int rpmsg_ioctl(FAR const char *cpuname, int cmd, unsigned 
long arg);
 int rpmsg_panic(FAR const char *cpuname);
 void rpmsg_dump_all(void);
 
+#ifdef CONFIG_RPMSG_TRACE
+void rpmsg_trace(FAR const char *name, bool bt, FAR const void *buf,
+                 size_t len, FAR const char *format, ...)
+                 printf_like(5, 6);
+void rpmsg_vtrace(FAR const char *name, bool bt, FAR const void *buf,
+                  size_t len, FAR const char *format, va_list ap)
+                  printf_like(5, 0);
+#else
+#  define rpmsg_trace(name, bt, buf, len, format, ...) \
+     do \
+       { \
+         (void)(name); \
+         (void)(buf); \
+         (void)(len); \
+       } \
+     while (0)
+#  define rpmsg_vtrace(name, bt, buf, len, format, ap) \
+     do \
+       { \
+         (void)(name); \
+         (void)(buf); \
+         (void)(len); \
+       } \
+     while (0)
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/nuttx/sched_note.h b/include/nuttx/sched_note.h
index 316df77320d..f509047a603 100644
--- a/include/nuttx/sched_note.h
+++ b/include/nuttx/sched_note.h
@@ -306,6 +306,7 @@ enum note_tag_e
   NOTE_TAG_SCHED,
   NOTE_TAG_VIDEO,
   NOTE_TAG_WIRLESS,
+  NOTE_TAG_RPMSG,
 
   /* Always last */
 

Reply via email to