From: Masami Hiramatsu <mhiramat@kernel.org>
To: Huang Shijie <shijie.huang@arm.com>
Cc: "David Long" <dave.long@linaro.org>,
"Catalin Marinas" <catalin.marinas@arm.com>,
"Will Deacon" <will.deacon@arm.com>,
"Sandeepa Prabhu" <sandeepa.s.prabhu@gmail.com>,
"William Cohen" <wcohen@redhat.com>,
"Pratyush Anand" <panand@redhat.com>,
"Steve Capper" <steve.capper@linaro.org>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
"Marc Zyngier" <marc.zyngier@arm.com>,
"Mark Rutland" <mark.rutland@arm.com>,
"Petr Mladek" <pmladek@suse.com>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"John Blackwood" <john.blackwood@ccur.com>,
"Feng Kan" <fkan@apm.com>, "Zi Shen Lim" <zlim.lnx@gmail.com>,
"Dave P Martin" <Dave.Martin@arm.com>,
"Yang Shi" <yang.shi@linaro.org>,
"Vladimir Murzin" <Vladimir.Murzin@arm.com>,
"Kees Cook" <keescook@chromium.org>,
"Suzuki K. Poulose" <suzuki.poulose@arm.com>,
"Mark Brown" <broonie@kernel.org>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Ard Biesheuvel" <ard.biesheuvel@linaro.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Mark Salyzyn" <salyzyn@android.com>,
"James Morse" <james.morse@arm.com>,
"Christoffer Dall" <christoffer.dall@linaro.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Robin Murphy" <Robin.Murphy@arm.com>,
"Jens Wiklander" <jens.wiklander@linaro.org>,
"Balamurugan Shanmugam" <bshanmugam@apm.com>
Subject: Re: [PATCH v12 05/10] arm64: Kprobes with single stepping support
Date: Wed, 18 May 2016 12:29:35 +0900 [thread overview]
Message-ID: <20160518122935.39fd7acc63d6f9c17fcbe275@kernel.org> (raw)
In-Reply-To: <20160517085807.GA842@sha-win-210.asiapac.arm.com>
On Tue, 17 May 2016 16:58:09 +0800
Huang Shijie <shijie.huang@arm.com> wrote:
> On Wed, Apr 27, 2016 at 02:53:00PM -0400, David Long wrote:
> > +
> > +/*
> > + * Interrupts need to be disabled before single-step mode is set, and not
> > + * reenabled until after single-step mode ends.
> > + * Without disabling interrupt on local CPU, there is a chance of
> > + * interrupt occurrence in the period of exception return and start of
> > + * out-of-line single-step, that result in wrongly single stepping
> > + * into the interrupt handler.
> > + */
> > +static void __kprobes kprobes_save_local_irqflag(struct pt_regs *regs)
> > +{
> > + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
>
> Why not add a parameter for this function to save the @kcb?
Good catch, it should use same kcb of caller.
>
> > +
> > + kcb->saved_irqflag = regs->pstate;
> > + regs->pstate |= PSR_I_BIT;
> > +}
> > +
> > +static void __kprobes kprobes_restore_local_irqflag(struct pt_regs *regs)
> > +{
> > + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
> ditto.
>
> > +
> > + if (kcb->saved_irqflag & PSR_I_BIT)
> > + regs->pstate |= PSR_I_BIT;
> > + else
> > + regs->pstate &= ~PSR_I_BIT;
> > +}
> > +
> > +static void __kprobes
> > +set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr)
> > +{
> > + kcb->ss_ctx.ss_pending = true;
> > + kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
> > +}
> > +
> > +static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb)
> > +{
> > + kcb->ss_ctx.ss_pending = false;
> > + kcb->ss_ctx.match_addr = 0;
> > +}
> > +
> > +static void __kprobes setup_singlestep(struct kprobe *p,
> > + struct pt_regs *regs,
> > + struct kprobe_ctlblk *kcb, int reenter)
> > +{
> > + unsigned long slot;
> > +
> > + if (reenter) {
> > + save_previous_kprobe(kcb);
> > + set_current_kprobe(p);
> > + kcb->kprobe_status = KPROBE_REENTER;
> > + } else {
> > + kcb->kprobe_status = KPROBE_HIT_SS;
> > + }
> > +
> > + if (p->ainsn.insn) {
> > + /* prepare for single stepping */
> > + slot = (unsigned long)p->ainsn.insn;
> > +
> > + set_ss_context(kcb, slot); /* mark pending ss */
> > +
> > + if (kcb->kprobe_status == KPROBE_REENTER)
> > + spsr_set_debug_flag(regs, 0);
> > +
> > + /* IRQs and single stepping do not mix well. */
> > + kprobes_save_local_irqflag(regs);
> > + kernel_enable_single_step(regs);
> > + instruction_pointer(regs) = slot;
> > + } else {
> > + BUG();
You'd better use BUG_ON(!p->ainsn.insn);
> > + }
> > +}
> > +
> > +static int __kprobes reenter_kprobe(struct kprobe *p,
> > + struct pt_regs *regs,
> > + struct kprobe_ctlblk *kcb)
> > +{
> > + switch (kcb->kprobe_status) {
> > + case KPROBE_HIT_SSDONE:
> > + case KPROBE_HIT_ACTIVE:
> > + kprobes_inc_nmissed_count(p);
> > + setup_singlestep(p, regs, kcb, 1);
> > + break;
> > + case KPROBE_HIT_SS:
> > + case KPROBE_REENTER:
> > + pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr);
> > + dump_kprobe(p);
> > + BUG();
> > + break;
> > + default:
> > + WARN_ON(1);
> > + return 0;
> > + }
> > +
> > + return 1;
> > +}
> > +
> > +static void __kprobes
> > +post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
> > +{
> > + struct kprobe *cur = kprobe_running();
> > +
> > + if (!cur)
> > + return;
> > +
> > + /* return addr restore if non-branching insn */
> > + if (cur->ainsn.restore.type == RESTORE_PC) {
> > + instruction_pointer(regs) = cur->ainsn.restore.addr;
> > + if (!instruction_pointer(regs))
> > + BUG();
> > + }
> > +
> > + /* restore back original saved kprobe variables and continue */
> > + if (kcb->kprobe_status == KPROBE_REENTER) {
> > + restore_previous_kprobe(kcb);
> > + return;
> > + }
> > + /* call post handler */
> > + kcb->kprobe_status = KPROBE_HIT_SSDONE;
> > + if (cur->post_handler) {
> > + /* post_handler can hit breakpoint and single step
> > + * again, so we enable D-flag for recursive exception.
> > + */
> > + cur->post_handler(cur, regs, 0);
> > + }
> > +
> > + reset_current_kprobe();
> > +}
> > +
> > +int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
> > +{
> > + struct kprobe *cur = kprobe_running();
> > + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
> > +
> > + switch (kcb->kprobe_status) {
> > + case KPROBE_HIT_SS:
> > + case KPROBE_REENTER:
> > + /*
> > + * We are here because the instruction being single
> > + * stepped caused a page fault. We reset the current
> > + * kprobe and the ip points back to the probe address
> > + * and allow the page fault handler to continue as a
> > + * normal page fault.
> > + */
> > + instruction_pointer(regs) = (unsigned long)cur->addr;
> > + if (!instruction_pointer(regs))
> > + BUG();
This can be BUG_ON(!instruction_pointer(regs)).
> > + if (kcb->kprobe_status == KPROBE_REENTER)
> > + restore_previous_kprobe(kcb);
> > + else
> > + reset_current_kprobe();
> > +
> > + break;
> > + case KPROBE_HIT_ACTIVE:
> > + case KPROBE_HIT_SSDONE:
> > + /*
> > + * We increment the nmissed count for accounting,
> > + * we can also use npre/npostfault count for accounting
> > + * these specific fault cases.
> > + */
> > + kprobes_inc_nmissed_count(cur);
> > +
> > + /*
> > + * We come here because instructions in the pre/post
> > + * handler caused the page_fault, this could happen
> > + * if handler tries to access user space by
> > + * copy_from_user(), get_user() etc. Let the
> > + * user-specified handler try to fix it first.
> > + */
> > + if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
> > + return 1;
> > +
> > + /*
> > + * In case the user-specified fault handler returned
> > + * zero, try to fix up.
> > + */
> > + if (fixup_exception(regs))
> > + return 1;
> > + }
> > + return 0;
> > +}
> > +
> > +int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
> > + unsigned long val, void *data)
> > +{
> > + return NOTIFY_DONE;
> > +}
> > +
> > +static void __kprobes kprobe_handler(struct pt_regs *regs)
> > +{
> > + struct kprobe *p, *cur_kprobe;
> > + struct kprobe_ctlblk *kcb;
> > + unsigned long addr = instruction_pointer(regs);
> > +
> > + kcb = get_kprobe_ctlblk();
> > + cur_kprobe = kprobe_running();
> > +
> > + p = get_kprobe((kprobe_opcode_t *) addr);
> > +
> > + if (p) {
> > + if (cur_kprobe) {
> > + if (reenter_kprobe(p, regs, kcb))
> > + return;
> > + } else {
> > + /* Probe hit */
> > + set_current_kprobe(p);
> > + kcb->kprobe_status = KPROBE_HIT_ACTIVE;
> > +
> > + /*
> > + * If we have no pre-handler or it returned 0, we
> > + * continue with normal processing. If we have a
> > + * pre-handler and it returned non-zero, it prepped
> > + * for calling the break_handler below on re-entry,
> > + * so get out doing nothing more here.
> > + *
> > + * pre_handler can hit a breakpoint and can step thru
> > + * before return, keep PSTATE D-flag enabled until
> > + * pre_handler return back.
> > + */
> > + if (!p->pre_handler || !p->pre_handler(p, regs)) {
> > + kcb->kprobe_status = KPROBE_HIT_SS;
> The above line is duplicated.
> You will set KPROBE_HIT_SS in the setup_singlestep.
Right.
>
> > + setup_singlestep(p, regs, kcb, 0);
> > + return;
> > + }
> > + }
> > + } else if ((le32_to_cpu(*(kprobe_opcode_t *) addr) ==
> > + BRK64_OPCODE_KPROBES) && cur_kprobe) {
> > + /* We probably hit a jprobe. Call its break handler. */
> > + if (cur_kprobe->break_handler &&
> > + cur_kprobe->break_handler(cur_kprobe, regs)) {
> > + kcb->kprobe_status = KPROBE_HIT_SS;
> ditto
> > + setup_singlestep(cur_kprobe, regs, kcb, 0);
> > + return;
> > + }
> > + }
> > + /*
> > + * The breakpoint instruction was removed right
> > + * after we hit it. Another cpu has removed
> > + * either a probepoint or a debugger breakpoint
> > + * at this address. In either case, no further
> > + * handling of this interrupt is appropriate.
> > + * Return back to original instruction, and continue.
> > + */
> > +}
Thanks,
--
Masami Hiramatsu <mhiramat@kernel.org>
next prev parent reply other threads:[~2016-05-18 3:29 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-27 18:52 [PATCH v12 00/10] arm64: Add kernel probes (kprobes) support David Long
2016-04-27 18:52 ` [PATCH v12 01/10] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature David Long
2016-04-28 16:08 ` Marc Zyngier
2016-05-13 19:07 ` David Long
2016-05-17 9:14 ` Huang Shijie
2016-05-20 4:18 ` David Long
2016-04-27 18:52 ` [PATCH v12 02/10] arm64: Add more test functions to insn.c David Long
2016-04-27 18:52 ` [PATCH v12 03/10] arm64: add conditional instruction simulation support David Long
2016-04-27 18:52 ` [PATCH v12 04/10] arm64: Blacklist non-kprobe-able symbols David Long
2016-04-27 18:53 ` [PATCH v12 05/10] arm64: Kprobes with single stepping support David Long
2016-05-12 15:01 ` James Morse
2016-05-18 4:04 ` Masami Hiramatsu
2016-05-20 5:16 ` David Long
2016-05-17 8:58 ` Huang Shijie
2016-05-18 3:29 ` Masami Hiramatsu [this message]
2016-05-26 19:25 ` David Long
2016-05-26 15:40 ` David Long
2016-05-17 9:10 ` Huang Shijie
2016-06-01 5:15 ` David Long
2016-04-27 18:53 ` [PATCH v12 06/10] arm64: Treat all entry code as non-kprobe-able David Long
2016-05-12 14:49 ` James Morse
2016-05-20 5:28 ` David Long
2016-05-26 15:26 ` David Long
2016-04-27 18:53 ` [PATCH v12 07/10] arm64: kprobes instruction simulation support David Long
2016-05-19 1:52 ` Huang Shijie
2016-05-26 19:28 ` David Long
2016-04-27 18:53 ` [PATCH v12 08/10] arm64: Add trampoline code for kretprobes David Long
2016-04-27 18:53 ` [PATCH v12 09/10] arm64: Add kernel return probes support (kretprobes) David Long
2016-04-27 18:53 ` [PATCH v12 10/10] kprobes: Add arm64 case in kprobe example module David Long
2016-05-17 9:57 ` Huang Shijie
2016-05-17 10:24 ` Mark Brown
2016-05-18 1:31 ` Huang Shijie
2016-05-11 15:33 ` [PATCH v12 00/10] arm64: Add kernel probes (kprobes) support James Morse
2016-05-12 2:26 ` Li Bin
2016-05-13 20:02 ` David Long
2016-05-18 2:24 ` Huang Shijie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160518122935.39fd7acc63d6f9c17fcbe275@kernel.org \
--to=mhiramat@kernel.org \
--cc=Dave.Martin@arm.com \
--cc=Robin.Murphy@arm.com \
--cc=Vladimir.Murzin@arm.com \
--cc=akpm@linux-foundation.org \
--cc=alex.bennee@linaro.org \
--cc=ard.biesheuvel@linaro.org \
--cc=broonie@kernel.org \
--cc=bshanmugam@apm.com \
--cc=catalin.marinas@arm.com \
--cc=christoffer.dall@linaro.org \
--cc=dave.long@linaro.org \
--cc=fkan@apm.com \
--cc=gregkh@linuxfoundation.org \
--cc=james.morse@arm.com \
--cc=jens.wiklander@linaro.org \
--cc=john.blackwood@ccur.com \
--cc=keescook@chromium.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=mark.rutland@arm.com \
--cc=panand@redhat.com \
--cc=pmladek@suse.com \
--cc=salyzyn@android.com \
--cc=sandeepa.s.prabhu@gmail.com \
--cc=shijie.huang@arm.com \
--cc=steve.capper@linaro.org \
--cc=suzuki.poulose@arm.com \
--cc=viresh.kumar@linaro.org \
--cc=wcohen@redhat.com \
--cc=will.deacon@arm.com \
--cc=yang.shi@linaro.org \
--cc=zlim.lnx@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome