2023-06-05 06:53:07

by Tiezhu Yang

[permalink] [raw]
Subject: [PATCH v5 0/6] Add uprobes support for LoongArch

v5:
-- Rebased on 6.4rc5
-- Like arm64, add user_enable_single_step() in arch_uprobe_pre_xol(),
add user_disable_single_step() in arch_uprobe_{post,abort}_xol(),
suggested by Jeff and Huacai offline

v4:
-- Rebased on 6.4rc1
-- Fix problem about "perf probe -x /lib64/libc.so.6 malloc"

v3:
-- Check atomic instructions in insns_not_supported()
-- Remove five DIE_* definitions in kdebug.h

v2:
-- Move the functions to inst.c in patch #1
-- Pass around union for insns_not_supported(),
insns_need_simulation() and arch_simulate_insn()

v1:
-- Split the RFC patch #2 into two patches
-- Use larch_insn_gen_break() to generate break insns
for kprobes and uprobes
-- Pass around instruction word instead of union for
insns_not_supported(), insns_need_simulation() and
arch_simulate_insn() to avoid type conversion for callers
-- Add a simple test case for uprobes in the commit message

Tiezhu Yang (6):
LoongArch: Move three functions from kprobes.c to inst.c
LoongArch: Add larch_insn_gen_break() to generate break insns
LoongArch: Use larch_insn_gen_break() for kprobes
LoongArch: Add uprobes support
LoongArch: Check atomic instructions in insns_not_supported()
LoongArch: Remove five DIE_* definitions in kdebug.h

arch/loongarch/Kconfig | 3 +
arch/loongarch/include/asm/inst.h | 42 ++++++++++
arch/loongarch/include/asm/kdebug.h | 5 --
arch/loongarch/include/asm/kprobes.h | 2 +-
arch/loongarch/include/asm/uprobes.h | 35 ++++++++
arch/loongarch/kernel/Makefile | 1 +
arch/loongarch/kernel/inst.c | 54 +++++++++++++
arch/loongarch/kernel/kprobes.c | 75 ++++-------------
arch/loongarch/kernel/traps.c | 9 +--
arch/loongarch/kernel/uprobes.c | 152 +++++++++++++++++++++++++++++++++++
10 files changed, 306 insertions(+), 72 deletions(-)
create mode 100644 arch/loongarch/include/asm/uprobes.h
create mode 100644 arch/loongarch/kernel/uprobes.c

--
2.1.0



2023-06-05 06:55:48

by Tiezhu Yang

[permalink] [raw]
Subject: [PATCH v5 5/6] LoongArch: Check atomic instructions in insns_not_supported()

Like llsc instructions, the atomic memory access instructions should
not be supported for probing, check them in insns_not_supported().

Here is a simple example with CONFIG_UPROBE_EVENTS=y:

# cat pthread.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

static pthread_spinlock_t lock;
static pthread_t t1, t2;
static int count = 0;

void *t1_start(void *arg)
{
for (int i = 0; i < 10000; i++)
{
pthread_spin_lock(&lock);
count++;
pthread_spin_unlock(&lock);
}
}

void *t2_start(void *arg)
{
for (int i = 0; i < 20000; i++)
{
pthread_spin_lock(&lock);
count++;
pthread_spin_unlock(&lock);
}
}

int main()
{
int ret;

ret = pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
if (ret)
return -1;

ret = pthread_create(&t1, NULL, t1_start, NULL);
if (ret)
exit(1);

ret = pthread_create(&t2, NULL, t2_start, NULL);
if (ret)
exit(1);

pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_spin_destroy(&lock);

printf("%d\n", count);
return 0;
}
# gcc pthread.c -o /tmp/pthread
# objdump -d /lib64/libc.so.6 | grep -w "pthread_spin_lock" -A 5 | head -5
00000000000886a4 <pthread_spin_lock@@GLIBC_2.36>:
886a4: 0280040d addi.w $t1, $zero, 1(0x1)
886a8: 3869348c amswap_db.w $t0, $t1, $a0
886ac: 0040818c slli.w $t0, $t0, 0x0
886b0: 44003180 bnez $t0, 48(0x30) # 886e0 <pthread_spin_lock@@GLIBC_2.36+0x3c>
# cd /sys/kernel/debug/tracing
# echo > uprobe_events
# echo "p:myuprobe /lib64/libc.so.6:0x886a4" > uprobe_events

Without this patch:

# echo 1 > events/uprobes/enable
# echo 1 > tracing_on
# /tmp/pthread
Trace/breakpoint trap (core dumped)

With this patch:

# echo 1 > events/uprobes/enable
bash: echo: write error: Invalid argument

Reported-by: Hengqi Chen <[email protected]>
Closes: https://lore.kernel.org/all/SY4P282MB351877A70A0333C790FE85A5C09C9@SY4P282MB3518.AUSP282.PROD.OUTLOOK.COM/
Signed-off-by: Tiezhu Yang <[email protected]>
Tested-by: Jeff Xie <[email protected]>
---
arch/loongarch/include/asm/inst.h | 26 ++++++++++++++++++++++++++
arch/loongarch/kernel/inst.c | 6 ++++++
arch/loongarch/kernel/uprobes.c | 9 +++++----
3 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 01fb789..ea625c4 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -178,6 +178,32 @@ enum reg3_op {
amord_op = 0x70c7,
amxorw_op = 0x70c8,
amxord_op = 0x70c9,
+ ammaxw_op = 0x70ca,
+ ammaxd_op = 0x70cb,
+ amminw_op = 0x70cc,
+ ammind_op = 0x70cd,
+ ammaxwu_op = 0x70ce,
+ ammaxdu_op = 0x70cf,
+ amminwu_op = 0x70d0,
+ ammindu_op = 0x70d1,
+ amswapdbw_op = 0x70d2,
+ amswapdbd_op = 0x70d3,
+ amadddbw_op = 0x70d4,
+ amadddbd_op = 0x70d5,
+ amanddbw_op = 0x70d6,
+ amanddbd_op = 0x70d7,
+ amordbw_op = 0x70d8,
+ amordbd_op = 0x70d9,
+ amxordbw_op = 0x70da,
+ amxordbd_op = 0x70db,
+ ammaxdbw_op = 0x70dc,
+ ammaxdbd_op = 0x70dd,
+ ammindbw_op = 0x70de,
+ ammindbd_op = 0x70df,
+ ammaxdbwu_op = 0x70e0,
+ ammaxdbdu_op = 0x70e1,
+ ammindbwu_op = 0x70e2,
+ ammindbdu_op = 0x70e3,
fldgts_op = 0x70e8,
fldgtd_op = 0x70e9,
fldles_op = 0x70ea,
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index 1d7d579..ce25a63 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -135,6 +135,12 @@ void simu_branch(struct pt_regs *regs, union loongarch_instruction insn)

bool insns_not_supported(union loongarch_instruction insn)
{
+ switch (insn.reg3_format.opcode) {
+ case amswapw_op ... ammindbdu_op:
+ pr_notice("atomic memory access instructions are not supported\n");
+ return true;
+ }
+
switch (insn.reg2i14_format.opcode) {
case llw_op:
case lld_op:
diff --git a/arch/loongarch/kernel/uprobes.c b/arch/loongarch/kernel/uprobes.c
index 3aa0046..3a56443 100644
--- a/arch/loongarch/kernel/uprobes.c
+++ b/arch/loongarch/kernel/uprobes.c
@@ -15,10 +15,11 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
if (addr & 0x3)
return -EILSEQ;

- insn.word = auprobe->insn[0];
-
- if (insns_not_supported(insn))
- return -EINVAL;
+ for (int idx = ARRAY_SIZE(auprobe->insn) - 1; idx >= 0; idx--) {
+ insn.word = auprobe->insn[idx];
+ if (insns_not_supported(insn))
+ return -EINVAL;
+ }

if (insns_need_simulation(insn)) {
auprobe->ixol[0] = larch_insn_gen_nop();
--
2.1.0


2023-06-05 06:57:48

by Tiezhu Yang

[permalink] [raw]
Subject: [PATCH v5 3/6] LoongArch: Use larch_insn_gen_break() for kprobes

For now, we can use larch_insn_gen_break() to define KPROBE_BP_INSN and
KPROBE_SSTEPBP_INSN. Because larch_insn_gen_break() returns instruction
word, define kprobe_opcode_t as u32, then do some small changes related
with type conversion, no functional change intended.

Signed-off-by: Tiezhu Yang <[email protected]>
Tested-by: Jeff Xie <[email protected]>
---
arch/loongarch/include/asm/kprobes.h | 2 +-
arch/loongarch/kernel/kprobes.c | 33 ++++++++++++++-------------------
2 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/arch/loongarch/include/asm/kprobes.h b/arch/loongarch/include/asm/kprobes.h
index 798020a..7ef7a0f 100644
--- a/arch/loongarch/include/asm/kprobes.h
+++ b/arch/loongarch/include/asm/kprobes.h
@@ -22,7 +22,7 @@ do { \

#define kretprobe_blacklist_size 0

-typedef union loongarch_instruction kprobe_opcode_t;
+typedef u32 kprobe_opcode_t;

/* Architecture specific copy of original instruction */
struct arch_specific_insn {
diff --git a/arch/loongarch/kernel/kprobes.c b/arch/loongarch/kernel/kprobes.c
index 08c78d2..1835102 100644
--- a/arch/loongarch/kernel/kprobes.c
+++ b/arch/loongarch/kernel/kprobes.c
@@ -4,19 +4,8 @@
#include <linux/preempt.h>
#include <asm/break.h>

-static const union loongarch_instruction breakpoint_insn = {
- .reg0i15_format = {
- .opcode = break_op,
- .immediate = BRK_KPROBE_BP,
- }
-};
-
-static const union loongarch_instruction singlestep_insn = {
- .reg0i15_format = {
- .opcode = break_op,
- .immediate = BRK_KPROBE_SSTEPBP,
- }
-};
+#define KPROBE_BP_INSN larch_insn_gen_break(BRK_KPROBE_BP)
+#define KPROBE_SSTEPBP_INSN larch_insn_gen_break(BRK_KPROBE_SSTEPBP)

DEFINE_PER_CPU(struct kprobe *, current_kprobe);
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -24,7 +13,7 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
static void arch_prepare_ss_slot(struct kprobe *p)
{
p->ainsn.insn[0] = *p->addr;
- p->ainsn.insn[1] = singlestep_insn;
+ p->ainsn.insn[1] = KPROBE_SSTEPBP_INSN;
p->ainsn.restore = (unsigned long)p->addr + LOONGARCH_INSN_SIZE;
}
NOKPROBE_SYMBOL(arch_prepare_ss_slot);
@@ -37,17 +26,20 @@ NOKPROBE_SYMBOL(arch_prepare_simulate);

int arch_prepare_kprobe(struct kprobe *p)
{
+ union loongarch_instruction insn;
+
if ((unsigned long)p->addr & 0x3)
return -EILSEQ;

/* copy instruction */
p->opcode = *p->addr;
+ insn.word = p->opcode;

/* decode instruction */
- if (insns_not_supported(p->opcode))
+ if (insns_not_supported(insn))
return -EINVAL;

- if (insns_need_simulation(p->opcode)) {
+ if (insns_need_simulation(insn)) {
p->ainsn.insn = NULL;
} else {
p->ainsn.insn = get_insn_slot();
@@ -68,7 +60,7 @@ NOKPROBE_SYMBOL(arch_prepare_kprobe);
/* Install breakpoint in text */
void arch_arm_kprobe(struct kprobe *p)
{
- *p->addr = breakpoint_insn;
+ *p->addr = KPROBE_BP_INSN;
flush_insn_slot(p);
}
NOKPROBE_SYMBOL(arch_arm_kprobe);
@@ -163,6 +155,8 @@ NOKPROBE_SYMBOL(post_kprobe_handler);
static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb, int reenter)
{
+ union loongarch_instruction insn;
+
if (reenter) {
save_previous_kprobe(kcb);
set_current_kprobe(p);
@@ -178,7 +172,8 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
regs->csr_era = (unsigned long)p->ainsn.insn;
} else {
/* simulate single steping */
- arch_simulate_insn(p->opcode, regs);
+ insn.word = p->opcode;
+ arch_simulate_insn(insn, regs);
/* now go for post processing */
post_kprobe_handler(p, kcb, regs);
}
@@ -253,7 +248,7 @@ bool kprobe_breakpoint_handler(struct pt_regs *regs)
}
}

- if (addr->word != breakpoint_insn.word) {
+ if (*addr != KPROBE_BP_INSN) {
/*
* The breakpoint instruction was removed right
* after we hit it. Another cpu has removed
--
2.1.0


2023-06-05 07:02:03

by Tiezhu Yang

[permalink] [raw]
Subject: [PATCH v5 6/6] LoongArch: Remove five DIE_* definitions in kdebug.h

For now, DIE_PAGE_FAULT, DIE_BREAK, DIE_SSTEPBP, DIE_UPROBE
and DIE_UPROBE_XOL are not used by any code, remove them.

Suggested-by: Youling Tang <[email protected]>
Signed-off-by: Tiezhu Yang <[email protected]>
Tested-by: Jeff Xie <[email protected]>
---
arch/loongarch/include/asm/kdebug.h | 5 -----
1 file changed, 5 deletions(-)

diff --git a/arch/loongarch/include/asm/kdebug.h b/arch/loongarch/include/asm/kdebug.h
index d721b4b..c00ed87 100644
--- a/arch/loongarch/include/asm/kdebug.h
+++ b/arch/loongarch/include/asm/kdebug.h
@@ -13,11 +13,6 @@ enum die_val {
DIE_FP,
DIE_SIMD,
DIE_TRAP,
- DIE_PAGE_FAULT,
- DIE_BREAK,
- DIE_SSTEPBP,
- DIE_UPROBE,
- DIE_UPROBE_XOL,
};

#endif /* _ASM_LOONGARCH_KDEBUG_H */
--
2.1.0


2023-06-07 09:03:40

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v5 0/6] Add uprobes support for LoongArch

Hi, Jeff,

I queued this series at
https://github.com/chenhuacai/linux/commits/loongarch-next, could you
please test it when you have time? Thanks.

Huacai

On Mon, Jun 5, 2023 at 2:39 PM Tiezhu Yang <[email protected]> wrote:
>
> v5:
> -- Rebased on 6.4rc5
> -- Like arm64, add user_enable_single_step() in arch_uprobe_pre_xol(),
> add user_disable_single_step() in arch_uprobe_{post,abort}_xol(),
> suggested by Jeff and Huacai offline
>
> v4:
> -- Rebased on 6.4rc1
> -- Fix problem about "perf probe -x /lib64/libc.so.6 malloc"
>
> v3:
> -- Check atomic instructions in insns_not_supported()
> -- Remove five DIE_* definitions in kdebug.h
>
> v2:
> -- Move the functions to inst.c in patch #1
> -- Pass around union for insns_not_supported(),
> insns_need_simulation() and arch_simulate_insn()
>
> v1:
> -- Split the RFC patch #2 into two patches
> -- Use larch_insn_gen_break() to generate break insns
> for kprobes and uprobes
> -- Pass around instruction word instead of union for
> insns_not_supported(), insns_need_simulation() and
> arch_simulate_insn() to avoid type conversion for callers
> -- Add a simple test case for uprobes in the commit message
>
> Tiezhu Yang (6):
> LoongArch: Move three functions from kprobes.c to inst.c
> LoongArch: Add larch_insn_gen_break() to generate break insns
> LoongArch: Use larch_insn_gen_break() for kprobes
> LoongArch: Add uprobes support
> LoongArch: Check atomic instructions in insns_not_supported()
> LoongArch: Remove five DIE_* definitions in kdebug.h
>
> arch/loongarch/Kconfig | 3 +
> arch/loongarch/include/asm/inst.h | 42 ++++++++++
> arch/loongarch/include/asm/kdebug.h | 5 --
> arch/loongarch/include/asm/kprobes.h | 2 +-
> arch/loongarch/include/asm/uprobes.h | 35 ++++++++
> arch/loongarch/kernel/Makefile | 1 +
> arch/loongarch/kernel/inst.c | 54 +++++++++++++
> arch/loongarch/kernel/kprobes.c | 75 ++++-------------
> arch/loongarch/kernel/traps.c | 9 +--
> arch/loongarch/kernel/uprobes.c | 152 +++++++++++++++++++++++++++++++++++
> 10 files changed, 306 insertions(+), 72 deletions(-)
> create mode 100644 arch/loongarch/include/asm/uprobes.h
> create mode 100644 arch/loongarch/kernel/uprobes.c
>
> --
> 2.1.0
>

2023-06-12 07:45:53

by Jeff Xie

[permalink] [raw]
Subject: Re: [PATCH v5 0/6] Add uprobes support for LoongArch

On Wed, Jun 7, 2023 at 4:52 PM Huacai Chen <[email protected]> wrote:
>
> Hi, Jeff,
>
> I queued this series at
> https://github.com/chenhuacai/linux/commits/loongarch-next, could you
> please test it when you have time? Thanks.

I have tested this series and saw no errors while using uprobe, the
patchset looks good to me.

Tested-by: Jeff Xie <[email protected]>

>
> Huacai
>
> On Mon, Jun 5, 2023 at 2:39 PM Tiezhu Yang <[email protected]> wrote:
> >
> > v5:
> > -- Rebased on 6.4rc5
> > -- Like arm64, add user_enable_single_step() in arch_uprobe_pre_xol(),
> > add user_disable_single_step() in arch_uprobe_{post,abort}_xol(),
> > suggested by Jeff and Huacai offline
> >
> > v4:
> > -- Rebased on 6.4rc1
> > -- Fix problem about "perf probe -x /lib64/libc.so.6 malloc"
> >
> > v3:
> > -- Check atomic instructions in insns_not_supported()
> > -- Remove five DIE_* definitions in kdebug.h
> >
> > v2:
> > -- Move the functions to inst.c in patch #1
> > -- Pass around union for insns_not_supported(),
> > insns_need_simulation() and arch_simulate_insn()
> >
> > v1:
> > -- Split the RFC patch #2 into two patches
> > -- Use larch_insn_gen_break() to generate break insns
> > for kprobes and uprobes
> > -- Pass around instruction word instead of union for
> > insns_not_supported(), insns_need_simulation() and
> > arch_simulate_insn() to avoid type conversion for callers
> > -- Add a simple test case for uprobes in the commit message
> >
> > Tiezhu Yang (6):
> > LoongArch: Move three functions from kprobes.c to inst.c
> > LoongArch: Add larch_insn_gen_break() to generate break insns
> > LoongArch: Use larch_insn_gen_break() for kprobes
> > LoongArch: Add uprobes support
> > LoongArch: Check atomic instructions in insns_not_supported()
> > LoongArch: Remove five DIE_* definitions in kdebug.h
> >
> > arch/loongarch/Kconfig | 3 +
> > arch/loongarch/include/asm/inst.h | 42 ++++++++++
> > arch/loongarch/include/asm/kdebug.h | 5 --
> > arch/loongarch/include/asm/kprobes.h | 2 +-
> > arch/loongarch/include/asm/uprobes.h | 35 ++++++++
> > arch/loongarch/kernel/Makefile | 1 +
> > arch/loongarch/kernel/inst.c | 54 +++++++++++++
> > arch/loongarch/kernel/kprobes.c | 75 ++++-------------
> > arch/loongarch/kernel/traps.c | 9 +--
> > arch/loongarch/kernel/uprobes.c | 152 +++++++++++++++++++++++++++++++++++
> > 10 files changed, 306 insertions(+), 72 deletions(-)
> > create mode 100644 arch/loongarch/include/asm/uprobes.h
> > create mode 100644 arch/loongarch/kernel/uprobes.c
> >
> > --
> > 2.1.0
> >



--
Thanks,
JeffXie