[PATCH v12 01/14] unwind_user: Add user space unwinding API

Steven Rostedt posted 14 patches 3 months, 1 week ago
There is a newer version of this series
[PATCH v12 01/14] unwind_user: Add user space unwinding API
Posted by Steven Rostedt 3 months, 1 week ago
From: Josh Poimboeuf <jpoimboe@kernel.org>

Introduce a generic API for unwinding user stacks.

In order to expand user space unwinding to be able to handle more complex
scenarios, such as deferred unwinding and reading user space information,
create a generic interface that all architectures can use that support the
various unwinding methods.

This is an alternative method for handling user space stack traces from
the simple stack_trace_save_user() API. This does not replace that
interface, but this interface will be used to expand the functionality of
user space stack walking.

None of the structures introduced will be exposed to user space tooling.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 MAINTAINERS                       |  8 +++++
 arch/Kconfig                      |  3 ++
 include/linux/unwind_user.h       | 15 +++++++++
 include/linux/unwind_user_types.h | 31 +++++++++++++++++
 kernel/Makefile                   |  1 +
 kernel/unwind/Makefile            |  1 +
 kernel/unwind/user.c              | 55 +++++++++++++++++++++++++++++++
 7 files changed, 114 insertions(+)
 create mode 100644 include/linux/unwind_user.h
 create mode 100644 include/linux/unwind_user_types.h
 create mode 100644 kernel/unwind/Makefile
 create mode 100644 kernel/unwind/user.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 4bac4ea21b64..ed5705c4f7d9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25924,6 +25924,14 @@ F:	Documentation/driver-api/uio-howto.rst
 F:	drivers/uio/
 F:	include/linux/uio_driver.h
 
+USERSPACE STACK UNWINDING
+M:	Josh Poimboeuf <jpoimboe@kernel.org>
+M:	Steven Rostedt <rostedt@goodmis.org>
+S:	Maintained
+F:	include/linux/unwind*.h
+F:	kernel/unwind/
+
+
 UTIL-LINUX PACKAGE
 M:	Karel Zak <kzak@redhat.com>
 L:	util-linux@vger.kernel.org
diff --git a/arch/Kconfig b/arch/Kconfig
index a3308a220f86..ea59e5d7cc69 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -435,6 +435,9 @@ config HAVE_HARDLOCKUP_DETECTOR_ARCH
 	  It uses the same command line parameters, and sysctl interface,
 	  as the generic hardlockup detectors.
 
+config UNWIND_USER
+	bool
+
 config HAVE_PERF_REGS
 	bool
 	help
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
new file mode 100644
index 000000000000..aa7923c1384f
--- /dev/null
+++ b/include/linux/unwind_user.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_UNWIND_USER_H
+#define _LINUX_UNWIND_USER_H
+
+#include <linux/unwind_user_types.h>
+
+int unwind_user_start(struct unwind_user_state *state);
+int unwind_user_next(struct unwind_user_state *state);
+
+int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
+
+#define for_each_user_frame(state) \
+	for (unwind_user_start((state)); !(state)->done; unwind_user_next((state)))
+
+#endif /* _LINUX_UNWIND_USER_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
new file mode 100644
index 000000000000..6ed1b4ae74e1
--- /dev/null
+++ b/include/linux/unwind_user_types.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_UNWIND_USER_TYPES_H
+#define _LINUX_UNWIND_USER_TYPES_H
+
+#include <linux/types.h>
+
+enum unwind_user_type {
+	UNWIND_USER_TYPE_NONE,
+};
+
+struct unwind_stacktrace {
+	unsigned int	nr;
+	unsigned long	*entries;
+};
+
+struct unwind_user_frame {
+	s32 cfa_off;
+	s32 ra_off;
+	s32 fp_off;
+	bool use_fp;
+};
+
+struct unwind_user_state {
+	unsigned long ip;
+	unsigned long sp;
+	unsigned long fp;
+	enum unwind_user_type type;
+	bool done;
+};
+
+#endif /* _LINUX_UNWIND_USER_TYPES_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index 32e80dd626af..541186050251 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -55,6 +55,7 @@ obj-y += rcu/
 obj-y += livepatch/
 obj-y += dma/
 obj-y += entry/
+obj-y += unwind/
 obj-$(CONFIG_MODULES) += module/
 
 obj-$(CONFIG_KCMP) += kcmp.o
diff --git a/kernel/unwind/Makefile b/kernel/unwind/Makefile
new file mode 100644
index 000000000000..349ce3677526
--- /dev/null
+++ b/kernel/unwind/Makefile
@@ -0,0 +1 @@
+ obj-$(CONFIG_UNWIND_USER) += user.o
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
new file mode 100644
index 000000000000..d30449328981
--- /dev/null
+++ b/kernel/unwind/user.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+* Generic interfaces for unwinding user space
+*/
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <linux/unwind_user.h>
+
+int unwind_user_next(struct unwind_user_state *state)
+{
+	/* no implementation yet */
+	return -EINVAL;
+}
+
+int unwind_user_start(struct unwind_user_state *state)
+{
+	struct pt_regs *regs = task_pt_regs(current);
+
+	memset(state, 0, sizeof(*state));
+
+	if ((current->flags & PF_KTHREAD) || !user_mode(regs)) {
+		state->done = true;
+		return -EINVAL;
+	}
+
+	state->type = UNWIND_USER_TYPE_NONE;
+
+	state->ip = instruction_pointer(regs);
+	state->sp = user_stack_pointer(regs);
+	state->fp = frame_pointer(regs);
+
+	return 0;
+}
+
+int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries)
+{
+	struct unwind_user_state state;
+
+	trace->nr = 0;
+
+	if (!max_entries)
+		return -EINVAL;
+
+	if (current->flags & PF_KTHREAD)
+		return 0;
+
+	for_each_user_frame(&state) {
+		trace->entries[trace->nr++] = state.ip;
+		if (trace->nr >= max_entries)
+			break;
+	}
+
+	return 0;
+}
-- 
2.47.2
Re: [PATCH v12 01/14] unwind_user: Add user space unwinding API
Posted by Mathieu Desnoyers 3 months ago
On 2025-06-30 20:53, Steven Rostedt wrote:
> From: Josh Poimboeuf <jpoimboe@kernel.org>
> 
> Introduce a generic API for unwinding user stacks.
> 
> In order to expand user space unwinding to be able to handle more complex
> scenarios, such as deferred unwinding and reading user space information,
> create a generic interface that all architectures can use that support the
> various unwinding methods.
> 
> This is an alternative method for handling user space stack traces from
> the simple stack_trace_save_user() API. This does not replace that
> interface, but this interface will be used to expand the functionality of
> user space stack walking.
> 
> None of the structures introduced will be exposed to user space tooling.

Would it be possible to make those unwind APIs EXPORT_SYMBOL_GPL
so they are available for GPL kernel modules ?

Thanks,

Mathieu

> 
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
>   MAINTAINERS                       |  8 +++++
>   arch/Kconfig                      |  3 ++
>   include/linux/unwind_user.h       | 15 +++++++++
>   include/linux/unwind_user_types.h | 31 +++++++++++++++++
>   kernel/Makefile                   |  1 +
>   kernel/unwind/Makefile            |  1 +
>   kernel/unwind/user.c              | 55 +++++++++++++++++++++++++++++++
>   7 files changed, 114 insertions(+)
>   create mode 100644 include/linux/unwind_user.h
>   create mode 100644 include/linux/unwind_user_types.h
>   create mode 100644 kernel/unwind/Makefile
>   create mode 100644 kernel/unwind/user.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4bac4ea21b64..ed5705c4f7d9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25924,6 +25924,14 @@ F:	Documentation/driver-api/uio-howto.rst
>   F:	drivers/uio/
>   F:	include/linux/uio_driver.h
>   
> +USERSPACE STACK UNWINDING
> +M:	Josh Poimboeuf <jpoimboe@kernel.org>
> +M:	Steven Rostedt <rostedt@goodmis.org>
> +S:	Maintained
> +F:	include/linux/unwind*.h
> +F:	kernel/unwind/
> +
> +
>   UTIL-LINUX PACKAGE
>   M:	Karel Zak <kzak@redhat.com>
>   L:	util-linux@vger.kernel.org
> diff --git a/arch/Kconfig b/arch/Kconfig
> index a3308a220f86..ea59e5d7cc69 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -435,6 +435,9 @@ config HAVE_HARDLOCKUP_DETECTOR_ARCH
>   	  It uses the same command line parameters, and sysctl interface,
>   	  as the generic hardlockup detectors.
>   
> +config UNWIND_USER
> +	bool
> +
>   config HAVE_PERF_REGS
>   	bool
>   	help
> diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
> new file mode 100644
> index 000000000000..aa7923c1384f
> --- /dev/null
> +++ b/include/linux/unwind_user.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _LINUX_UNWIND_USER_H
> +#define _LINUX_UNWIND_USER_H
> +
> +#include <linux/unwind_user_types.h>
> +
> +int unwind_user_start(struct unwind_user_state *state);
> +int unwind_user_next(struct unwind_user_state *state);
> +
> +int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
> +
> +#define for_each_user_frame(state) \
> +	for (unwind_user_start((state)); !(state)->done; unwind_user_next((state)))
> +
> +#endif /* _LINUX_UNWIND_USER_H */

[...]


-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com
Re: [PATCH v12 01/14] unwind_user: Add user space unwinding API
Posted by Steven Rostedt 3 months ago
On Fri, 4 Jul 2025 14:20:54 -0400
Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote:

> > None of the structures introduced will be exposed to user space tooling.  
> 
> Would it be possible to make those unwind APIs EXPORT_SYMBOL_GPL
> so they are available for GPL kernel modules ?

I'm OK with that, but others tend to complain about EXPORT_SYMBOL_GPL
for functions not used by modules in the kernel. But I personally feel
that LTTng should get an exception for that rule ;-)

-- Steve
Re: [PATCH v12 01/14] unwind_user: Add user space unwinding API
Posted by Steven Rostedt 3 months ago
On Mon, 7 Jul 2025 15:42:45 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Fri, 4 Jul 2025 14:20:54 -0400
> Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote:
> 
> > > None of the structures introduced will be exposed to user space tooling.    
> > 
> > Would it be possible to make those unwind APIs EXPORT_SYMBOL_GPL
> > so they are available for GPL kernel modules ?  
> 
> I'm OK with that, but others tend to complain about EXPORT_SYMBOL_GPL
> for functions not used by modules in the kernel. But I personally feel
> that LTTng should get an exception for that rule ;-)

I just noticed that this was to patch 1. The functions here probably
shouldn't be exported as they are more internal to the infrastructure.

In fact, I think I'll move that macro into the user.c code. I don't
think it should be used outside that function. And the
unwind_user_start/next() could also be static functions.

-- Steve
Re: [PATCH v12 01/14] unwind_user: Add user space unwinding API
Posted by Mathieu Desnoyers 3 months ago
On 2025-06-30 20:53, Steven Rostedt wrote:
[...]
> diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
> new file mode 100644
> index 000000000000..aa7923c1384f
> --- /dev/null
> +++ b/include/linux/unwind_user.h
[...]
> +
> +int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
> +
> +#define for_each_user_frame(state) \
> +	for (unwind_user_start((state)); !(state)->done; unwind_user_next((state)))

You can remove the () around "state" when it's already surrounded by parentheses:

+#define for_each_user_frame(state) \
+	for (unwind_user_start(state); !(state)->done; unwind_user_next(state))

Thanks,

Mathieu

-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com