ping//Re: [PATCH -next 2/2] riscv: implemented branch simulate instructions

chenlifu chenlifu at huawei.com
Sun Jul 4 19:09:35 PDT 2021



在 2021/6/29 10:34, Chen Lifu 写道:
> 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>:
> ...
> 
> 0000000000000080 <.L7>:
>    80:	414986bb          	subw	a3,s3,s4
>    84:	4785                	li	a5,1
>    86:	00d7c363          	blt	a5,a3,8c <.L8>
>    8a:	2485                	addiw	s1,s1,1
> 
> 000000000000008c <.L8>:
>    8c:	012987bb          	addw	a5,s3,s2
>    90:	4711                	li	a4,4
>    92:	00f75363          	bge	a4,a5,98 <.L9>
>    96:	2485                	addiw	s1,s1,1
> ...
> 
> 00000000000000aa <.L11>:
>    aa:	01299363          	bne	s3,s2,b0 <.L12>
>    ae:	2485                	addiw	s1,s1,1
> 
> 00000000000000b0 <.L12>:
>    b0:	012a0363          	beq	s4,s2,b6 <.L13>
>    b4:	2485                	addiw	s1,s1,1
> ...
> 
> 00000000000000c2 <.L14>:
>    c2:	0009861b          	sext.w	a2,s3
>    c6:	013a7363          	bgeu	s4,s3,cc <.L15>
>    ca:	2485                	addiw	s1,s1,1
> ...
> 
> 00000000000000d2 <.L16>:
>    d2:	00e7e363          	bltu	a5,a4,d8 <.L17>
>    d6:	2485                	addiw	s1,s1,1
> ...
> 
> Test the kprobe-based event tracing in qemu-system-riscv64:
> First, install the kprobe test module:
> insmod /root/kprobe_test.ko
> 
> Then, add probes as new events at the branch instructions,
> i.e. blt, bge, bne, beq, bgeu and bltu.
> The following errors occur due to the instructions not allowed to probe yet:
> echo "p:blt kprobe_test:kprobe_test_branch+0x86 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
> echo "p:bge kprobe_test:kprobe_test_branch+0x92 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
> echo "p:bne kprobe_test:kprobe_test_branch+0xaa epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
> echo "p:beq kprobe_test:kprobe_test_branch+0xb0 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
> echo "p:bgeu kprobe_test:kprobe_test_branch+0xc6 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
> echo "p:bltu kprobe_test:kprobe_test_branch+0xd2 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> sh: write error: Invalid argument
> 
> This patch implemented the branch simulate instructions and allowed to probe them.
> Merge this patch and perform the test again, the test results are as follows:
> First, add probes at the branch instructions:
> echo "p:blt kprobe_test:kprobe_test_branch+0x86 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo "p:bge kprobe_test:kprobe_test_branch+0x92 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo "p:bne kprobe_test:kprobe_test_branch+0xaa epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo "p:beq kprobe_test:kprobe_test_branch+0xb0 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo "p:bgeu kprobe_test:kprobe_test_branch+0xc6 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo "p:bltu kprobe_test:kprobe_test_branch+0xd2 epc=%epc opcode=+0(%epc):x32" >> /sys/kernel/debug/tracing/kprobe_events
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/blt/enable
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/bge/enable
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/bne/enable
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/beq/enable
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/bgeu/enable
> echo 1 > /sys/kernel/debug/tracing/events/kprobes/bltu/enable
> 
> Then, do something to run to the probes.
> After that, see the traced information:
> cat /sys/kernel/debug/tracing/trace
> sysctl-63      [001] d...  2505.263969: blt: (kprobe_test_branch+0x86/0x10e [kprobe_test]) epc=0xffffffff016122f8 opcode=0x100073
> sysctl-63      [001] d...  2505.263991: bge: (kprobe_test_branch+0x92/0x10e [kprobe_test]) epc=0xffffffff01612304 opcode=0x100073
> sysctl-63      [001] d...  2505.264001: bne: (kprobe_test_branch+0xaa/0x10e [kprobe_test]) epc=0xffffffff0161231c opcode=0x100073
> sysctl-63      [001] d...  2505.264011: beq: (kprobe_test_branch+0xb0/0x10e [kprobe_test]) epc=0xffffffff01612322 opcode=0x100073
> sysctl-63      [001] d...  2505.264019: bgeu: (kprobe_test_branch+0xc6/0x10e [kprobe_test]) epc=0xffffffff01612338 opcode=0x100073
> sysctl-63      [001] d...  2505.264027: bltu: (kprobe_test_branch+0xd2/0x10e [kprobe_test]) epc=0xffffffff01612344 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 branch instructions
> have been replaced by 'ebreak(0x100073)' instructions.
> 
> The pesudoinstructions of the branch instructions,
> i.e. bnez, beqz, blez, bgez, bltz, bgtz, bleu, bgtu and ble
> are allowed to probe as well.
> 
> --------
> 
> Signed-off-by: Chen Lifu <chenlifu at huawei.com>
> ---
>   arch/riscv/kernel/probes/decode-insn.c   |  3 +-
>   arch/riscv/kernel/probes/simulate-insn.c | 78 ++++++++++++++++++++++++
>   2 files changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c
> index 5eb03fb61450..64f6183b4717 100644
> --- a/arch/riscv/kernel/probes/decode-insn.c
> +++ b/arch/riscv/kernel/probes/decode-insn.c
> @@ -38,11 +38,10 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
>   	RISCV_INSN_REJECTED(c_ebreak,		insn);
>   #endif
>   
> -	RISCV_INSN_REJECTED(branch,		insn);
> -
>   	RISCV_INSN_SET_SIMULATE(jal,		insn);
>   	RISCV_INSN_SET_SIMULATE(jalr,		insn);
>   	RISCV_INSN_SET_SIMULATE(auipc,		insn);
> +	RISCV_INSN_SET_SIMULATE(branch,		insn);
>   
>   	return INSN_GOOD;
>   }
> diff --git a/arch/riscv/kernel/probes/simulate-insn.c b/arch/riscv/kernel/probes/simulate-insn.c
> index b81719522d5c..efc989b28859 100644
> --- a/arch/riscv/kernel/probes/simulate-insn.c
> +++ b/arch/riscv/kernel/probes/simulate-insn.c
> @@ -117,3 +117,81 @@ bool __kprobes simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *re
>   
>   	return true;
>   }
> +
> +#define branch_rs1_idx(opcode) \
> +	(((opcode) >> 15) & 0x1f)
> +
> +#define branch_rs2_idx(opcode) \
> +	(((opcode) >> 20) & 0x1f)
> +
> +#define branch_funct3(opcode) \
> +	(((opcode) >> 12) & 0x7)
> +
> +#define branch_imm(opcode) \
> +	(((((opcode) >> 8 ) & 0xf ) << 1 ) | \
> +	 ((((opcode) >> 25) & 0x3f) << 5 ) | \
> +	 ((((opcode) >> 7 ) & 0x1 ) << 11) | \
> +	 ((((opcode) >> 31) & 0x1 ) << 12))
> +
> +#define branch_offset(opcode) \
> +	sign_extend32((branch_imm(opcode)), 12)
> +
> +#define BRANCH_BEQ	0x0
> +#define BRANCH_BNE	0x1
> +#define BRANCH_BLT	0x4
> +#define BRANCH_BGE	0x5
> +#define BRANCH_BLTU	0x6
> +#define BRANCH_BGEU	0x7
> +
> +bool __kprobes simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *regs)
> +{
> +	/*
> +	 * branch instructions:
> +	 *      31    30       25 24 20 19 15 14    12 11       8    7      6      0
> +	 * | imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode |
> +	 *     1           6        5     5      3         4         1         7
> +	 *     imm[12|10:5]        rs2   rs1    000       imm[4:1|11]       1100011  BEQ
> +	 *     imm[12|10:5]        rs2   rs1    001       imm[4:1|11]       1100011  BNE
> +	 *     imm[12|10:5]        rs2   rs1    100       imm[4:1|11]       1100011  BLT
> +	 *     imm[12|10:5]        rs2   rs1    101       imm[4:1|11]       1100011  BGE
> +	 *     imm[12|10:5]        rs2   rs1    110       imm[4:1|11]       1100011  BLTU
> +	 *     imm[12|10:5]        rs2   rs1    111       imm[4:1|11]       1100011  BGEU
> +	 */
> +
> +	s32 offset;
> +	s32 offset_tmp;
> +	unsigned long rs1_val;
> +	unsigned long rs2_val;
> +
> +	if (!rv_insn_reg_get_val(regs, branch_rs1_idx(opcode), &rs1_val) ||
> +	    !rv_insn_reg_get_val(regs, branch_rs2_idx(opcode), &rs2_val))
> +		return false;
> +
> +	offset_tmp = branch_offset(opcode);
> +	switch (branch_funct3(opcode)) {
> +	case BRANCH_BEQ:
> +		offset = (rs1_val == rs2_val) ? offset_tmp : 4;
> +		break;
> +	case BRANCH_BNE:
> +		offset = (rs1_val != rs2_val) ? offset_tmp : 4;
> +		break;
> +	case BRANCH_BLT:
> +		offset = ((long)rs1_val < (long)rs2_val) ? offset_tmp : 4;
> +		break;
> +	case BRANCH_BGE:
> +		offset = ((long)rs1_val >= (long)rs2_val) ? offset_tmp : 4;
> +		break;
> +	case BRANCH_BLTU:
> +		offset = (rs1_val < rs2_val) ? offset_tmp : 4;
> +		break;
> +	case BRANCH_BGEU:
> +		offset = (rs1_val >= rs2_val) ? offset_tmp : 4;
> +		break;
> +	default:
> +		return false;
> +	}
> +
> +	instruction_pointer_set(regs, addr + offset);
> +
> +	return true;
> +}
> 



More information about the linux-riscv mailing list