[PATCH v3 11/14] powerpc/kprobes: Support kprobes on prefixed instructions
Nicholas Piggin
npiggin at gmail.com
Fri Feb 28 12:47:48 AEDT 2020
Jordan Niethe's on February 27, 2020 10:58 am:
> On Wed, Feb 26, 2020 at 6:18 PM Nicholas Piggin <npiggin at gmail.com> wrote:
>>
>> Jordan Niethe's on February 26, 2020 2:07 pm:
>> > @@ -136,11 +148,14 @@ int arch_prepare_kprobe(struct kprobe *p)
>> > }
>> >
>> > if (!ret) {
>> > - patch_instruction(p->ainsn.insn, *p->addr);
>> > + patch_instruction(&p->ainsn.insn[0], p->addr[0]);
>> > + if (IS_PREFIX(insn))
>> > + patch_instruction(&p->ainsn.insn[1], p->addr[1]);
>> > p->opcode = *p->addr;
>>
>> Not to single out this hunk or this patch even, but what do you reckon
>> about adding an instruction data type, and then use that in all these
>> call sites rather than adding the extra arg or doing the extra copy
>> manually in each place depending on prefix?
>>
>> instrs_are_equal, get_user_instr, analyse_instr, patch_instruction,
>> etc., would all take this new instr. Places that open code a memory
>> access like your MCE change need some accessor
>>
>> instr = *(unsigned int *)(instr_addr);
>> - if (!analyse_instr(&op, &tmp, instr, PPC_NO_SUFFIX)) {
>> + if (IS_PREFIX(instr))
>> + suffix = *(unsigned int *)(instr_addr + 4);
>>
>> Becomes
>> read_instr(instr_addr, &instr);
>> if (!analyse_instr(&op, &tmp, instr)) ...
>>
>> etc.
> Daniel Axtens also talked about this and my reasons not to do so were
> pretty unconvincing, so I started trying something like this. One
Okay.
> thing I have been wondering is how pervasive should the new type be.
I wouldn't mind it being quite pervasive. We have to be careful not
to copy it directly to/from memory now, but if we have accessors to
do all that with, I think it should be okay.
> Below is data type I have started using, which I think works
> reasonably for replacing unsigned ints everywhere (like within
> code-patching.c). In a few architecture independent places such as
> uprobes which want to do ==, etc the union type does not work so well.
There will be some places you have to make the boundary. I would start
by just making it a powerpc thing, but possibly there is or could be
some generic helpers. How does something like x86 cope with this?
> I will have the next revision of the series start using a type.
Thanks for doing that.
>
> diff --git a/arch/powerpc/include/asm/inst.h b/arch/powerpc/include/asm/inst.h
> new file mode 100644
> index 000000000000..50adb3dbdeb4
> --- /dev/null
> +++ b/arch/powerpc/include/asm/inst.h
> @@ -0,0 +1,87 @@
> +
> +#ifndef _ASM_INST_H
> +#define _ASM_INST_H
> +
> +#ifdef __powerpc64__
> +
> +/* 64 bit Instruction */
> +
> +typedef struct {
> + unsigned int prefix;
> + unsigned int suffix;
u32?
> +} __packed ppc_prefixed_inst;
> +
> +typedef union ppc_inst {
> + unsigned int w;
> + ppc_prefixed_inst p;
> +} ppc_inst;
I'd make it a struct and use nameless structs/unions inside it (with
appropriate packed annotation):
struct ppc_inst {
union {
struct {
u32 word;
u32 pad;
};
struct {
u32 prefix;
u32 suffix;
};
};
};
> +
> +#define PPC_INST_IS_PREFIXED(inst) (((inst).w >> 26) == 1)
> +#define PPC_INST_LEN(inst) (PPC_INST_IS_PREFIXED((inst)) ?
> sizeof((inst).p) : sizeof((inst).w))
Good accessors, I'd make them all C inline functions and lower case.
> +
> +#define PPC_INST_NEW_WORD(x) ((ppc_inst) { .w = (x) })
> +#define PPC_INST_NEW_WORD_PAD(x) ((ppc_inst) { .p.prefix = (x),
> .p.suffix = (0x60000000) })
> +#define PPC_INST_NEW_PREFIXED(x, y) ((ppc_inst) { .p.prefix = (x),
> .p.suffix = (y) })
If these are widely used, I'd make them a bit shorter
#define PPC_INST(x)
#define PPC_INST_PREFIXED(x)
I'd also set padding to something invalid 0 or 0xffffffff for the first
case, and have your accessors check that rather than carrying around
another type of ppc_inst (prefixed, padded, non-padded).
> +
> +#define PPC_INST_WORD(x) ((x).w)
> +#define PPC_INST_PREFIX(x) (x.p.prefix)
> +#define PPC_INST_SUFFIX(x) (x.p.suffix)
> +#define PPC_INST_EMPTY(x) (PPC_INST_WORD(x) == 0)
I'd avoid simple accessors like this completely. If they have any use
it would be to ensure you don't try to use prefix/suffix on a
non-prefixed instruction for example. If you want to do that I'd use
inline functions for it.
> +
> +#define DEREF_PPC_INST_PTR(ptr) \
> +({ \
> + ppc_inst __inst; \
> + __inst.w = *(unsigned int *)(ptr); \
> + if (PPC_INST_IS_PREFIXED(__inst)) \
> + __inst.p = *(ppc_prefixed_inst *)(ptr); \
> + __inst; \
> +})
I'd go an inline with shorter lowercase names. ppc_inst_read(&inst);
> +#define PPC_INST_NEXT(ptr) ((ptr) += PPC_INST_LEN(DEREF_PPC_INST_PTR((ptr))))
> +#define PPC_INST_PREV(ptr) ((ptr) -= PPC_INST_LEN(DEREF_PPC_INST_PTR((ptr))))
Wouldn't bother with this accessor, caller could ptr += ppc_inst_len(inst)
> +#define PPC_INST_EQ(x, y) \
> +({ \
> + long pic_ret = 0; \
> + pic_ret = (PPC_INST_PREFIX(x) == PPC_INST_PREFIX(y)); \
> + if (pic_ret) { \
> + if (PPC_INST_IS_PREFIXED(x) && PPC_INST_IS_PREFIXED(y)) { \
> + pic_ret = (PPC_INST_SUFFIX(x) == PPC_INST_SUFFIX(y)); \
> + } else { \
> + pic_ret = 0; \
> + } \
> + } \
> + pic_ret; \
> +})
static inline bool ppc_inst_eq(struct ppc_inst x, struct ppc_inst y)
{
return !memcmp(&x, &y, sizeof(struct ppc_inst));
}
If all accessors and initalisers are such that the padding gets set,
that'll work.
Thanks,
Nick
More information about the Linuxppc-dev
mailing list