[v1,1/4] LoongArch: Move three functions from kprobes.c to inst.h
Commit Message
The following three functions will be used for uprobes, move them
from kprobes.c to inst.h:
insns_not_supported()
insns_need_simulation()
arch_simulate_insn()
This is preparation for later patch, no functionality change.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
arch/loongarch/include/asm/inst.h | 39 +++++++++++++++++++++++++++++++++
arch/loongarch/kernel/kprobes.c | 46 ++-------------------------------------
2 files changed, 41 insertions(+), 44 deletions(-)
Comments
On Wed, 2023-04-12 at 18:04 +0800, Tiezhu Yang wrote:
> +static inline bool insns_not_supported(union loongarch_instruction insn)
This function seems long enough (to me) not to use "static inline".
Note that most part of this function belongs to a cold path, and IMO
it's bad to inline a cold path into every caller.
> +{
> + switch (insn.reg2i14_format.opcode) {
> + case llw_op:
> + case lld_op:
> + case scw_op:
> + case scd_op:
> + pr_notice("kprobe: ll and sc instructions are not supported\n");
> + return true;
> + }
> +
> + switch (insn.reg1i21_format.opcode) {
> + case bceqz_op:
> + pr_notice("kprobe: bceqz and bcnez instructions are not supported\n");
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static inline bool insns_need_simulation(union loongarch_instruction insn)
> +{
> + if (is_pc_ins(&insn))
> + return true;
> +
> + if (is_branch_ins(&insn))
> + return true;
> +
> + return false;
I'd write "return is_pc_ins(&insn) || is_branch_ins(&insn);" here, but
there is no behavioral difference anyway.
> +}
On 04/12/2023 06:39 PM, Xi Ruoyao wrote:
> On Wed, 2023-04-12 at 18:04 +0800, Tiezhu Yang wrote:
>> +static inline bool insns_not_supported(union loongarch_instruction insn)
>
> This function seems long enough (to me) not to use "static inline".
> Note that most part of this function belongs to a cold path, and IMO
> it's bad to inline a cold path into every caller.
OK, I will move the three functions from kprobes.c to inst.c.
>
>> +{
>> + switch (insn.reg2i14_format.opcode) {
>> + case llw_op:
>> + case lld_op:
>> + case scw_op:
>> + case scd_op:
>> + pr_notice("kprobe: ll and sc instructions are not supported\n");
>> + return true;
>> + }
>> +
>> + switch (insn.reg1i21_format.opcode) {
>> + case bceqz_op:
>> + pr_notice("kprobe: bceqz and bcnez instructions are not supported\n");
>> + return true;
>> + }
>> +
>> + return false;
>> +}
>> +
>> +static inline bool insns_need_simulation(union loongarch_instruction insn)
>> +{
>> + if (is_pc_ins(&insn))
>> + return true;
>> +
>> + if (is_branch_ins(&insn))
>> + return true;
>> +
>> + return false;
>
> I'd write "return is_pc_ins(&insn) || is_branch_ins(&insn);" here, but
> there is no behavioral difference anyway.
I prefer leave it as it is.
Thanks,
Tiezhu
@@ -409,6 +409,45 @@ static inline bool is_self_loop_ins(union loongarch_instruction *ip, struct pt_r
void simu_pc(struct pt_regs *regs, union loongarch_instruction insn);
void simu_branch(struct pt_regs *regs, union loongarch_instruction insn);
+static inline bool insns_not_supported(union loongarch_instruction insn)
+{
+ switch (insn.reg2i14_format.opcode) {
+ case llw_op:
+ case lld_op:
+ case scw_op:
+ case scd_op:
+ pr_notice("kprobe: ll and sc instructions are not supported\n");
+ return true;
+ }
+
+ switch (insn.reg1i21_format.opcode) {
+ case bceqz_op:
+ pr_notice("kprobe: bceqz and bcnez instructions are not supported\n");
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool insns_need_simulation(union loongarch_instruction insn)
+{
+ if (is_pc_ins(&insn))
+ return true;
+
+ if (is_branch_ins(&insn))
+ return true;
+
+ return false;
+}
+
+static inline void arch_simulate_insn(union loongarch_instruction insn, struct pt_regs *regs)
+{
+ if (is_pc_ins(&insn))
+ simu_pc(regs, insn);
+ else if (is_branch_ins(&insn))
+ simu_branch(regs, insn);
+}
+
int larch_insn_read(void *addr, u32 *insnp);
int larch_insn_write(void *addr, u32 insn);
int larch_insn_patch_text(void *addr, u32 insn);
@@ -21,48 +21,6 @@ static const union loongarch_instruction singlestep_insn = {
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-static bool insns_not_supported(union loongarch_instruction insn)
-{
- switch (insn.reg2i14_format.opcode) {
- case llw_op:
- case lld_op:
- case scw_op:
- case scd_op:
- pr_notice("kprobe: ll and sc instructions are not supported\n");
- return true;
- }
-
- switch (insn.reg1i21_format.opcode) {
- case bceqz_op:
- pr_notice("kprobe: bceqz and bcnez instructions are not supported\n");
- return true;
- }
-
- return false;
-}
-NOKPROBE_SYMBOL(insns_not_supported);
-
-static bool insns_need_simulation(struct kprobe *p)
-{
- if (is_pc_ins(&p->opcode))
- return true;
-
- if (is_branch_ins(&p->opcode))
- return true;
-
- return false;
-}
-NOKPROBE_SYMBOL(insns_need_simulation);
-
-static void arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
-{
- if (is_pc_ins(&p->opcode))
- simu_pc(regs, p->opcode);
- else if (is_branch_ins(&p->opcode))
- simu_branch(regs, p->opcode);
-}
-NOKPROBE_SYMBOL(arch_simulate_insn);
-
static void arch_prepare_ss_slot(struct kprobe *p)
{
p->ainsn.insn[0] = *p->addr;
@@ -89,7 +47,7 @@ int arch_prepare_kprobe(struct kprobe *p)
if (insns_not_supported(p->opcode))
return -EINVAL;
- if (insns_need_simulation(p)) {
+ if (insns_need_simulation(p->opcode)) {
p->ainsn.insn = NULL;
} else {
p->ainsn.insn = get_insn_slot();
@@ -220,7 +178,7 @@ 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, regs);
+ arch_simulate_insn(p->opcode, regs);
/* now go for post processing */
post_kprobe_handler(p, kcb, regs);
}