diff mbox series

[V5,19/21] riscv: compat: ptrace: Add compat_arch_ptrace implement

Message ID 20220201150545.1512822-20-guoren@kernel.org
State New
Headers show
Series riscv: compat: Add COMPAT mode support for rv64 | expand

Commit Message

Guo Ren Feb. 1, 2022, 3:05 p.m. UTC
From: Guo Ren <guoren@linux.alibaba.com>

Now, you can use native gdb on riscv64 for rv32 app debugging.

$ uname -a
Linux buildroot 5.16.0-rc4-00036-gbef6b82fdf23-dirty #53 SMP Mon Dec 20 23:06:53 CST 2021 riscv64 GNU/Linux
$ cat /proc/cpuinfo
processor       : 0
hart            : 0
isa             : rv64imafdcsuh
mmu             : sv48

$ file /bin/busybox
/bin/busybox: setuid ELF 32-bit LSB shared object, UCB RISC-V, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv32-ilp32d.so.1, for GNU/Linux 5.15.0, stripped
$ file /usr/bin/gdb
/usr/bin/gdb: ELF 32-bit LSB shared object, UCB RISC-V, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-riscv32-ilp32d.so.1, for GNU/Linux 5.15.0, stripped
$ /usr/bin/gdb /bin/busybox
GNU gdb (GDB) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...
Reading symbols from /bin/busybox...
(No debugging symbols found in /bin/busybox)
(gdb) b main
Breakpoint 1 at 0x8ddc
(gdb) r
Starting program: /bin/busybox
Failed to read a valid object file image from memory.

Breakpoint 1, 0x555a8ddc in main ()
(gdb) i r
ra             0x77df0b74       0x77df0b74
sp             0x7fdd3d10       0x7fdd3d10
gp             0x5567e800       0x5567e800 <bb_common_bufsiz1+160>
tp             0x77f64280       0x77f64280
t0             0x0      0
t1             0x555a6fac       1431990188
t2             0x77dd8db4       2011008436
fp             0x7fdd3e34       0x7fdd3e34
s1             0x7fdd3e34       2145205812
a0             0xffffffff       -1
a1             0x2000   8192
a2             0x7fdd3e3c       2145205820
a3             0x0      0
a4             0x7fdd3d30       2145205552
a5             0x555a8dc0       1431997888
a6             0x77f2c170       2012397936
a7             0x6a7c7a2f       1786542639
s2             0x0      0
s3             0x0      0
s4             0x555a8dc0       1431997888
s5             0x77f8a3a8       2012783528
s6             0x7fdd3e3c       2145205820
s7             0x5567cecc       1432866508
--Type <RET> for more, q to quit, c to continue without paging--
s8             0x1      1
s9             0x0      0
s10            0x55634448       1432568904
s11            0x0      0
t3             0x77df0bb8       2011106232
t4             0x42fc   17148
t5             0x0      0
t6             0x40     64
pc             0x555a8ddc       0x555a8ddc <main+28>
(gdb) si
0x555a78f0 in mallopt@plt ()
(gdb) c
Continuing.
BusyBox v1.34.1 (2021-12-19 22:39:48 CST) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
   or: busybox --list[-full]
...
[Inferior 1 (process 107) exited normally]
(gdb) q

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
---
 arch/riscv/kernel/ptrace.c | 87 +++++++++++++++++++++++++++++++++++---
 1 file changed, 82 insertions(+), 5 deletions(-)

Comments

Palmer Dabbelt Feb. 23, 2022, 1:42 a.m. UTC | #1
On Tue, 01 Feb 2022 07:05:43 PST (-0800), guoren@kernel.org wrote:
> From: Guo Ren <guoren@linux.alibaba.com>
>
> Now, you can use native gdb on riscv64 for rv32 app debugging.
>
> $ uname -a
> Linux buildroot 5.16.0-rc4-00036-gbef6b82fdf23-dirty #53 SMP Mon Dec 20 23:06:53 CST 2021 riscv64 GNU/Linux
> $ cat /proc/cpuinfo
> processor       : 0
> hart            : 0
> isa             : rv64imafdcsuh
> mmu             : sv48
>
> $ file /bin/busybox
> /bin/busybox: setuid ELF 32-bit LSB shared object, UCB RISC-V, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv32-ilp32d.so.1, for GNU/Linux 5.15.0, stripped
> $ file /usr/bin/gdb
> /usr/bin/gdb: ELF 32-bit LSB shared object, UCB RISC-V, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-riscv32-ilp32d.so.1, for GNU/Linux 5.15.0, stripped
> $ /usr/bin/gdb /bin/busybox
> GNU gdb (GDB) 10.2
> Copyright (C) 2021 Free Software Foundation, Inc.
> License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
> ...
> Reading symbols from /bin/busybox...
> (No debugging symbols found in /bin/busybox)
> (gdb) b main
> Breakpoint 1 at 0x8ddc
> (gdb) r
> Starting program: /bin/busybox
> Failed to read a valid object file image from memory.
>
> Breakpoint 1, 0x555a8ddc in main ()
> (gdb) i r
> ra             0x77df0b74       0x77df0b74
> sp             0x7fdd3d10       0x7fdd3d10
> gp             0x5567e800       0x5567e800 <bb_common_bufsiz1+160>
> tp             0x77f64280       0x77f64280
> t0             0x0      0
> t1             0x555a6fac       1431990188
> t2             0x77dd8db4       2011008436
> fp             0x7fdd3e34       0x7fdd3e34
> s1             0x7fdd3e34       2145205812
> a0             0xffffffff       -1
> a1             0x2000   8192
> a2             0x7fdd3e3c       2145205820
> a3             0x0      0
> a4             0x7fdd3d30       2145205552
> a5             0x555a8dc0       1431997888
> a6             0x77f2c170       2012397936
> a7             0x6a7c7a2f       1786542639
> s2             0x0      0
> s3             0x0      0
> s4             0x555a8dc0       1431997888
> s5             0x77f8a3a8       2012783528
> s6             0x7fdd3e3c       2145205820
> s7             0x5567cecc       1432866508
> --Type <RET> for more, q to quit, c to continue without paging--
> s8             0x1      1
> s9             0x0      0
> s10            0x55634448       1432568904
> s11            0x0      0
> t3             0x77df0bb8       2011106232
> t4             0x42fc   17148
> t5             0x0      0
> t6             0x40     64
> pc             0x555a8ddc       0x555a8ddc <main+28>
> (gdb) si
> 0x555a78f0 in mallopt@plt ()
> (gdb) c
> Continuing.
> BusyBox v1.34.1 (2021-12-19 22:39:48 CST) multi-call binary.
> BusyBox is copyrighted by many authors between 1998-2015.
> Licensed under GPLv2. See source distribution for detailed
> copyright notices.
>
> Usage: busybox [function [arguments]...]
>    or: busybox --list[-full]
> ...
> [Inferior 1 (process 107) exited normally]
> (gdb) q
>
> Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> Signed-off-by: Guo Ren <guoren@kernel.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Palmer Dabbelt <palmer@dabbelt.com>
> ---
>  arch/riscv/kernel/ptrace.c | 87 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 82 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
> index a89243730153..bb387593a121 100644
> --- a/arch/riscv/kernel/ptrace.c
> +++ b/arch/riscv/kernel/ptrace.c
> @@ -12,6 +12,7 @@
>  #include <asm/thread_info.h>
>  #include <asm/switch_to.h>
>  #include <linux/audit.h>
> +#include <linux/compat.h>
>  #include <linux/ptrace.h>
>  #include <linux/elf.h>
>  #include <linux/regset.h>
> @@ -111,11 +112,6 @@ static const struct user_regset_view riscv_user_native_view = {
>  	.n = ARRAY_SIZE(riscv_user_regset),
>  };
>
> -const struct user_regset_view *task_user_regset_view(struct task_struct *task)
> -{
> -	return &riscv_user_native_view;
> -}
> -
>  struct pt_regs_offset {
>  	const char *name;
>  	int offset;
> @@ -273,3 +269,84 @@ __visible void do_syscall_trace_exit(struct pt_regs *regs)
>  		trace_sys_exit(regs, regs_return_value(regs));
>  #endif
>  }
> +
> +#ifdef CONFIG_COMPAT
> +static int compat_riscv_gpr_get(struct task_struct *target,
> +				const struct user_regset *regset,
> +				struct membuf to)
> +{
> +	struct compat_user_regs_struct cregs;
> +
> +	regs_to_cregs(&cregs, task_pt_regs(target));
> +
> +	return membuf_write(&to, &cregs,
> +			    sizeof(struct compat_user_regs_struct));
> +}
> +
> +static int compat_riscv_gpr_set(struct task_struct *target,
> +				const struct user_regset *regset,
> +				unsigned int pos, unsigned int count,
> +				const void *kbuf, const void __user *ubuf)
> +{
> +	int ret;
> +	struct compat_user_regs_struct cregs;
> +
> +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
> +
> +	cregs_to_regs(&cregs, task_pt_regs(target));
> +
> +	return ret;
> +}
> +
> +static const struct user_regset compat_riscv_user_regset[] = {
> +	[REGSET_X] = {
> +		.core_note_type = NT_PRSTATUS,
> +		.n = ELF_NGREG,
> +		.size = sizeof(compat_elf_greg_t),
> +		.align = sizeof(compat_elf_greg_t),
> +		.regset_get = compat_riscv_gpr_get,
> +		.set = compat_riscv_gpr_set,
> +	},
> +#ifdef CONFIG_FPU
> +	[REGSET_F] = {
> +		.core_note_type = NT_PRFPREG,
> +		.n = ELF_NFPREG,
> +		.size = sizeof(elf_fpreg_t),
> +		.align = sizeof(elf_fpreg_t),
> +		.regset_get = riscv_fpr_get,
> +		.set = riscv_fpr_set,
> +	},
> +#endif
> +};
> +
> +static const struct user_regset_view compat_riscv_user_native_view = {
> +	.name = "riscv",
> +	.e_machine = EM_RISCV,
> +	.regsets = compat_riscv_user_regset,
> +	.n = ARRAY_SIZE(compat_riscv_user_regset),
> +};
> +
> +long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
> +			compat_ulong_t caddr, compat_ulong_t cdata)
> +{
> +	long ret = -EIO;
> +
> +	switch (request) {
> +	default:
> +		ret = compat_ptrace_request(child, request, caddr, cdata);
> +		break;
> +	}
> +
> +	return ret;
> +}
> +#endif /* CONFIG_COMPAT */
> +
> +const struct user_regset_view *task_user_regset_view(struct task_struct *task)
> +{
> +#ifdef CONFIG_COMPAT
> +	if (test_tsk_thread_flag(task, TIF_32BIT))
> +		return &compat_riscv_user_native_view;
> +	else
> +#endif
> +		return &riscv_user_native_view;
> +}

Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com>
diff mbox series

Patch

diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
index a89243730153..bb387593a121 100644
--- a/arch/riscv/kernel/ptrace.c
+++ b/arch/riscv/kernel/ptrace.c
@@ -12,6 +12,7 @@ 
 #include <asm/thread_info.h>
 #include <asm/switch_to.h>
 #include <linux/audit.h>
+#include <linux/compat.h>
 #include <linux/ptrace.h>
 #include <linux/elf.h>
 #include <linux/regset.h>
@@ -111,11 +112,6 @@  static const struct user_regset_view riscv_user_native_view = {
 	.n = ARRAY_SIZE(riscv_user_regset),
 };
 
-const struct user_regset_view *task_user_regset_view(struct task_struct *task)
-{
-	return &riscv_user_native_view;
-}
-
 struct pt_regs_offset {
 	const char *name;
 	int offset;
@@ -273,3 +269,84 @@  __visible void do_syscall_trace_exit(struct pt_regs *regs)
 		trace_sys_exit(regs, regs_return_value(regs));
 #endif
 }
+
+#ifdef CONFIG_COMPAT
+static int compat_riscv_gpr_get(struct task_struct *target,
+				const struct user_regset *regset,
+				struct membuf to)
+{
+	struct compat_user_regs_struct cregs;
+
+	regs_to_cregs(&cregs, task_pt_regs(target));
+
+	return membuf_write(&to, &cregs,
+			    sizeof(struct compat_user_regs_struct));
+}
+
+static int compat_riscv_gpr_set(struct task_struct *target,
+				const struct user_regset *regset,
+				unsigned int pos, unsigned int count,
+				const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+	struct compat_user_regs_struct cregs;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
+
+	cregs_to_regs(&cregs, task_pt_regs(target));
+
+	return ret;
+}
+
+static const struct user_regset compat_riscv_user_regset[] = {
+	[REGSET_X] = {
+		.core_note_type = NT_PRSTATUS,
+		.n = ELF_NGREG,
+		.size = sizeof(compat_elf_greg_t),
+		.align = sizeof(compat_elf_greg_t),
+		.regset_get = compat_riscv_gpr_get,
+		.set = compat_riscv_gpr_set,
+	},
+#ifdef CONFIG_FPU
+	[REGSET_F] = {
+		.core_note_type = NT_PRFPREG,
+		.n = ELF_NFPREG,
+		.size = sizeof(elf_fpreg_t),
+		.align = sizeof(elf_fpreg_t),
+		.regset_get = riscv_fpr_get,
+		.set = riscv_fpr_set,
+	},
+#endif
+};
+
+static const struct user_regset_view compat_riscv_user_native_view = {
+	.name = "riscv",
+	.e_machine = EM_RISCV,
+	.regsets = compat_riscv_user_regset,
+	.n = ARRAY_SIZE(compat_riscv_user_regset),
+};
+
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+			compat_ulong_t caddr, compat_ulong_t cdata)
+{
+	long ret = -EIO;
+
+	switch (request) {
+	default:
+		ret = compat_ptrace_request(child, request, caddr, cdata);
+		break;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_COMPAT */
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+#ifdef CONFIG_COMPAT
+	if (test_tsk_thread_flag(task, TIF_32BIT))
+		return &compat_riscv_user_native_view;
+	else
+#endif
+		return &riscv_user_native_view;
+}