diff mbox series

[-next,1/2] riscv: implemented auipc simulate instruction

Message ID 20210629023455.280998-1-chenlifu@huawei.com (mailing list archive)
State New, archived
Headers show
Series [-next,1/2] riscv: implemented auipc simulate instruction | expand

Commit Message

chenlifu June 29, 2021, 2:34 a.m. UTC
To test the kprobe-based event tracing, we prepare
a kernel module 'kprobe_test.ko' to add the probes.
The assembly codes (partially) of the module are as follows:
...
0000000000000000 <kprobe_test_branch>:
...
0000000000000038 <.LVL1>:
  38:	00000597          	auipc	a1,0x0
  3c:	00058593          	mv	a1,a1
...

Test the kprobe-based event tracing in qemu-system-riscv64:
First, install the kprobe test module:
insmod /root/kprobe_test.ko

Then, add a probe as a new event at an 'auipc' instruction,
the following error occurs due to the instruction not allowed to probe yet:
echo "p:auipc kprobe_test:kprobe_test_branch+0x38 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
sh: write error: Invalid argument

This patch implemented the 'auipc' simulate instruction and allowed to probe it.
Merge this patch and perform the test again, the test results are as follows:
First, add a probe at the 'auipc' instruction:
echo "p:auipc kprobe_test:kprobe_test_branch+0x38 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/auipc/enable

Then, do something to run to the probe.
After that, see the traced information:
cat /sys/kernel/debug/tracing/trace
sysctl-58      [001] d...   179.126350: auipc: (kprobe_test_branch+0x38/0x10e [kprobe_test]) epc=0xffffffff016122aa opcode=0x100073

Now we can see the traced information.
The actual address of the symbol 'kprobe_test_branch' is as follows:
cat /proc/kallsyms | grep kprobe_test_branch
ffffffff01612272 t kprobe_test_branch   [kprobe_test]

Based on the traced information and the actual address of the symbol
'kprobe_test_branch', we can also see that the 'auipc' instruction
has been replaced by 'ebreak(0x100073)' instruction.

--------

Signed-off-by: Chen Lifu <chenlifu@huawei.com>
---
 arch/riscv/kernel/probes/decode-insn.c   |  2 +-
 arch/riscv/kernel/probes/simulate-insn.c | 34 ++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

Comments

Palmer Dabbelt July 22, 2021, 5:26 p.m. UTC | #1
On Mon, 28 Jun 2021 19:34:54 PDT (-0700), chenlifu@huawei.com wrote:
> To test the kprobe-based event tracing, we prepare
> a kernel module 'kprobe_test.ko' to add the probes.
> The assembly codes (partially) of the module are as follows:
> ...
> 0000000000000000 <kprobe_test_branch>:
> ...
> 0000000000000038 <.LVL1>:
>   38:	00000597          	auipc	a1,0x0
>   3c:	00058593          	mv	a1,a1
> ...
>
> Test the kprobe-based event tracing in qemu-system-riscv64:
> First, install the kprobe test module:
> insmod /root/kprobe_test.ko
>
> Then, add a probe as a new event at an 'auipc' instruction,
> the following error occurs due to the instruction not allowed to probe yet:
> echo "p:auipc kprobe_test:kprobe_test_branch+0x38 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
>
> This patch implemented the 'auipc' simulate instruction and allowed to probe it.
> Merge this patch and perform the test again, the test results are as follows:
> First, add a probe at the 'auipc' instruction:
> echo "p:auipc kprobe_test:kprobe_test_branch+0x38 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/auipc/enable
>
> Then, do something to run to the probe.
> After that, see the traced information:
> cat /sys/kernel/debug/tracing/trace
> sysctl-58      [001] d...   179.126350: auipc: (kprobe_test_branch+0x38/0x10e [kprobe_test]) epc=0xffffffff016122aa opcode=0x100073
>
> Now we can see the traced information.
> The actual address of the symbol 'kprobe_test_branch' is as follows:
> cat /proc/kallsyms | grep kprobe_test_branch
> ffffffff01612272 t kprobe_test_branch   [kprobe_test]
>
> Based on the traced information and the actual address of the symbol
> 'kprobe_test_branch', we can also see that the 'auipc' instruction
> has been replaced by 'ebreak(0x100073)' instruction.
>
> --------
>
> Signed-off-by: Chen Lifu <chenlifu@huawei.com>
> ---
>  arch/riscv/kernel/probes/decode-insn.c   |  2 +-
>  arch/riscv/kernel/probes/simulate-insn.c | 34 ++++++++++++++++++++++++
>  2 files changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c
> index 0ed043acc882..5eb03fb61450 100644
> --- a/arch/riscv/kernel/probes/decode-insn.c
> +++ b/arch/riscv/kernel/probes/decode-insn.c
> @@ -38,11 +38,11 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
>  	RISCV_INSN_REJECTED(c_ebreak,		insn);
>  #endif
>
> -	RISCV_INSN_REJECTED(auipc,		insn);
>  	RISCV_INSN_REJECTED(branch,		insn);
>
>  	RISCV_INSN_SET_SIMULATE(jal,		insn);
>  	RISCV_INSN_SET_SIMULATE(jalr,		insn);
> +	RISCV_INSN_SET_SIMULATE(auipc,		insn);
>
>  	return INSN_GOOD;
>  }
> diff --git a/arch/riscv/kernel/probes/simulate-insn.c b/arch/riscv/kernel/probes/simulate-insn.c
> index 2519ce26377d..b81719522d5c 100644
> --- a/arch/riscv/kernel/probes/simulate-insn.c
> +++ b/arch/riscv/kernel/probes/simulate-insn.c
> @@ -83,3 +83,37 @@ bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *reg
>
>  	return ret;
>  }
> +
> +#define auipc_rd_idx(opcode) \
> +	((opcode >> 7) & 0x1f)
> +
> +#define auipc_imm(opcode) \
> +	((((opcode) >> 12) & 0xfffff) << 12)
> +
> +#if __riscv_xlen == 64
> +#define auipc_offset(opcode)	sign_extend64(auipc_imm(opcode), 31)
> +#elif __riscv_xlen == 32
> +#define auipc_offset(opcode)	auipc_imm(opcode)
> +#else
> +#error "Unexpected __riscv_xlen"
> +#endif
> +
> +bool __kprobes simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs)
> +{
> +	/*
> +	 * auipc instruction:
> +	 *  31        12 11 7 6      0
> +	 * | imm[31:12] | rd | opcode |
> +	 *        20       5     7
> +	 */
> +
> +	u32 rd_idx = auipc_rd_idx(opcode);
> +	unsigned long rd_val = addr + auipc_offset(opcode);
> +
> +	if (!rv_insn_reg_set_val(regs, rd_idx, rd_val))
> +		return false;
> +
> +	instruction_pointer_set(regs, addr + 4);
> +
> +	return true;
> +}

Thanks.  These are on for-next, with the checkpatch errors fixed and the 
commit messages mostly removed -- it was all pretty awkwardly phrased so 
I didn't want to clean it up.
diff mbox series

Patch

diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c
index 0ed043acc882..5eb03fb61450 100644
--- a/arch/riscv/kernel/probes/decode-insn.c
+++ b/arch/riscv/kernel/probes/decode-insn.c
@@ -38,11 +38,11 @@  riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
 	RISCV_INSN_REJECTED(c_ebreak,		insn);
 #endif
 
-	RISCV_INSN_REJECTED(auipc,		insn);
 	RISCV_INSN_REJECTED(branch,		insn);
 
 	RISCV_INSN_SET_SIMULATE(jal,		insn);
 	RISCV_INSN_SET_SIMULATE(jalr,		insn);
+	RISCV_INSN_SET_SIMULATE(auipc,		insn);
 
 	return INSN_GOOD;
 }
diff --git a/arch/riscv/kernel/probes/simulate-insn.c b/arch/riscv/kernel/probes/simulate-insn.c
index 2519ce26377d..b81719522d5c 100644
--- a/arch/riscv/kernel/probes/simulate-insn.c
+++ b/arch/riscv/kernel/probes/simulate-insn.c
@@ -83,3 +83,37 @@  bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *reg
 
 	return ret;
 }
+
+#define auipc_rd_idx(opcode) \
+	((opcode >> 7) & 0x1f)
+
+#define auipc_imm(opcode) \
+	((((opcode) >> 12) & 0xfffff) << 12)
+
+#if __riscv_xlen == 64
+#define auipc_offset(opcode)	sign_extend64(auipc_imm(opcode), 31)
+#elif __riscv_xlen == 32
+#define auipc_offset(opcode)	auipc_imm(opcode)
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+bool __kprobes simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs)
+{
+	/*
+	 * auipc instruction:
+	 *  31        12 11 7 6      0
+	 * | imm[31:12] | rd | opcode |
+	 *        20       5     7
+	 */
+
+	u32 rd_idx = auipc_rd_idx(opcode);
+	unsigned long rd_val = addr + auipc_offset(opcode);
+
+	if (!rv_insn_reg_set_val(regs, rd_idx, rd_val))
+		return false;
+
+	instruction_pointer_set(regs, addr + 4);
+
+	return true;
+}