mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
Probes update for v6.13:
Kprobes cleanups. Functionality does not change. - kprobes: Cleanup the config comment Adjust #endif comments. - kprobes: Cleanup collect_one_slot() and __disable_kprobe() Make fail fast to reduce code nested level. - kprobes: Use struct_size() in __get_insn_slot() Use struct_size() to avoid special macro. - x86/kprobes: Cleanup kprobes on ftrace code Use macro instead of direct field access/magic number, and avoid redundant instruction pointer setting. -----BEGIN PGP SIGNATURE----- iQFPBAABCgA5FiEEh7BulGwFlgAOi5DV2/sHvwUrPxsFAmc6vhwbHG1hc2FtaS5o aXJhbWF0c3VAZ21haWwuY29tAAoJENv7B78FKz8bxowIALFYrdLV2ofWRy7/lNkP 6Bv1DkBQ/Xy/ABZ4lAqdgTZrf7Cz8TdPZUL1UOowxW3Cl09PYcpqlUlw/XldvI5j fukkwL9rXNgJfYbau+QG9E5c7mNakexDLBKCZGvnDDuKj0f1aauhwZmpJbNgz1Y6 dUgfFgDJXSArnVKxfZvOhL1tbxYPJUhzNc339p8PVD8r/OUKEZo2EReds3DM40Zq wtwyKqWmawTjRud0ZtgkaWiK1d+QKa07h+GnXi1wUy98A2yGp3fcLuxvjBUMqsCD uzWkY3MikXIZJ/ijxUsMGBRisD4ozqozlQ4wIxCuahRntl9b/d9jXqKY7RTvy6Vw r+Y= =n4ST -----END PGP SIGNATURE----- Merge tag 'probes-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull probes updates from Masami Hiramatsu: "Kprobes cleanups. Functionality does not change. - kprobes: Cleanup the config comment Adjust #endif comments. - kprobes: Cleanup collect_one_slot() and __disable_kprobe() Make fail fast to reduce code nested level. - kprobes: Use struct_size() in __get_insn_slot() Use struct_size() to avoid special macro. - x86/kprobes: Cleanup kprobes on ftrace code Use macro instead of direct field access/magic number, and avoid redundant instruction pointer setting" * tag 'probes-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: x86/kprobes: Cleanup kprobes on ftrace code kprobes: Use struct_size() in __get_insn_slot() kprobes: Cleanup collect_one_slot() and __disable_kprobe() kprobes: Cleanup the config comment
This commit is contained in:
commit
a0e752bda2
@ -9,6 +9,7 @@
|
|||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
#include <linux/preempt.h>
|
#include <linux/preempt.h>
|
||||||
#include <linux/ftrace.h>
|
#include <linux/ftrace.h>
|
||||||
|
#include <asm/text-patching.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
@ -36,23 +37,25 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
|
|||||||
if (kprobe_running()) {
|
if (kprobe_running()) {
|
||||||
kprobes_inc_nmissed_count(p);
|
kprobes_inc_nmissed_count(p);
|
||||||
} else {
|
} else {
|
||||||
unsigned long orig_ip = regs->ip;
|
unsigned long orig_ip = instruction_pointer(regs);
|
||||||
|
|
||||||
/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
|
/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
|
||||||
regs->ip = ip + sizeof(kprobe_opcode_t);
|
instruction_pointer_set(regs, ip + INT3_INSN_SIZE);
|
||||||
|
|
||||||
__this_cpu_write(current_kprobe, p);
|
__this_cpu_write(current_kprobe, p);
|
||||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||||
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
||||||
/*
|
|
||||||
* Emulate singlestep (and also recover regs->ip)
|
|
||||||
* as if there is a 5byte nop
|
|
||||||
*/
|
|
||||||
regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
|
|
||||||
if (unlikely(p->post_handler)) {
|
if (unlikely(p->post_handler)) {
|
||||||
|
/*
|
||||||
|
* Emulate singlestep (and also recover regs->ip)
|
||||||
|
* as if there is a 5byte nop
|
||||||
|
*/
|
||||||
|
instruction_pointer_set(regs, ip + MCOUNT_INSN_SIZE);
|
||||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||||
p->post_handler(p, regs, 0);
|
p->post_handler(p, regs, 0);
|
||||||
}
|
}
|
||||||
regs->ip = orig_ip;
|
/* Recover IP address */
|
||||||
|
instruction_pointer_set(regs, orig_ip);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If pre_handler returns !0, it changes regs->ip. We have to
|
* If pre_handler returns !0, it changes regs->ip. We have to
|
||||||
|
@ -95,10 +95,6 @@ struct kprobe_insn_page {
|
|||||||
char slot_used[];
|
char slot_used[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KPROBE_INSN_PAGE_SIZE(slots) \
|
|
||||||
(offsetof(struct kprobe_insn_page, slot_used) + \
|
|
||||||
(sizeof(char) * (slots)))
|
|
||||||
|
|
||||||
static int slots_per_page(struct kprobe_insn_cache *c)
|
static int slots_per_page(struct kprobe_insn_cache *c)
|
||||||
{
|
{
|
||||||
return PAGE_SIZE/(c->insn_size * sizeof(kprobe_opcode_t));
|
return PAGE_SIZE/(c->insn_size * sizeof(kprobe_opcode_t));
|
||||||
@ -175,7 +171,7 @@ kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c)
|
|||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
/* All out of space. Need to allocate a new page. */
|
/* All out of space. Need to allocate a new page. */
|
||||||
kip = kmalloc(KPROBE_INSN_PAGE_SIZE(slots_per_page(c)), GFP_KERNEL);
|
kip = kmalloc(struct_size(kip, slot_used, slots_per_page(c)), GFP_KERNEL);
|
||||||
if (!kip)
|
if (!kip)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -206,29 +202,29 @@ static bool collect_one_slot(struct kprobe_insn_page *kip, int idx)
|
|||||||
{
|
{
|
||||||
kip->slot_used[idx] = SLOT_CLEAN;
|
kip->slot_used[idx] = SLOT_CLEAN;
|
||||||
kip->nused--;
|
kip->nused--;
|
||||||
if (kip->nused == 0) {
|
if (kip->nused != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Page is no longer in use. Free it unless
|
||||||
|
* it's the last one. We keep the last one
|
||||||
|
* so as not to have to set it up again the
|
||||||
|
* next time somebody inserts a probe.
|
||||||
|
*/
|
||||||
|
if (!list_is_singular(&kip->list)) {
|
||||||
/*
|
/*
|
||||||
* Page is no longer in use. Free it unless
|
* Record perf ksymbol unregister event before removing
|
||||||
* it's the last one. We keep the last one
|
* the page.
|
||||||
* so as not to have to set it up again the
|
|
||||||
* next time somebody inserts a probe.
|
|
||||||
*/
|
*/
|
||||||
if (!list_is_singular(&kip->list)) {
|
perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_OOL,
|
||||||
/*
|
(unsigned long)kip->insns, PAGE_SIZE, true,
|
||||||
* Record perf ksymbol unregister event before removing
|
kip->cache->sym);
|
||||||
* the page.
|
list_del_rcu(&kip->list);
|
||||||
*/
|
synchronize_rcu();
|
||||||
perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_OOL,
|
kip->cache->free(kip->insns);
|
||||||
(unsigned long)kip->insns, PAGE_SIZE, true,
|
kfree(kip);
|
||||||
kip->cache->sym);
|
|
||||||
list_del_rcu(&kip->list);
|
|
||||||
synchronize_rcu();
|
|
||||||
kip->cache->free(kip->insns);
|
|
||||||
kfree(kip);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int collect_garbage_slots(struct kprobe_insn_cache *c)
|
static int collect_garbage_slots(struct kprobe_insn_cache *c)
|
||||||
@ -353,8 +349,8 @@ struct kprobe_insn_cache kprobe_optinsn_slots = {
|
|||||||
/* .insn_size is initialized later */
|
/* .insn_size is initialized later */
|
||||||
.nr_garbage = 0,
|
.nr_garbage = 0,
|
||||||
};
|
};
|
||||||
#endif
|
#endif /* CONFIG_OPTPROBES */
|
||||||
#endif
|
#endif /* __ARCH_WANT_KPROBES_INSN_SLOT */
|
||||||
|
|
||||||
/* We have preemption disabled.. so it is safe to use __ versions */
|
/* We have preemption disabled.. so it is safe to use __ versions */
|
||||||
static inline void set_kprobe_instance(struct kprobe *kp)
|
static inline void set_kprobe_instance(struct kprobe *kp)
|
||||||
@ -1543,7 +1539,7 @@ static int check_ftrace_location(struct kprobe *p)
|
|||||||
if (ftrace_location(addr) == addr) {
|
if (ftrace_location(addr) == addr) {
|
||||||
#ifdef CONFIG_KPROBES_ON_FTRACE
|
#ifdef CONFIG_KPROBES_ON_FTRACE
|
||||||
p->flags |= KPROBE_FLAG_FTRACE;
|
p->flags |= KPROBE_FLAG_FTRACE;
|
||||||
#else /* !CONFIG_KPROBES_ON_FTRACE */
|
#else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1725,28 +1721,29 @@ static struct kprobe *__disable_kprobe(struct kprobe *p)
|
|||||||
if (unlikely(orig_p == NULL))
|
if (unlikely(orig_p == NULL))
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
if (!kprobe_disabled(p)) {
|
if (kprobe_disabled(p))
|
||||||
/* Disable probe if it is a child probe */
|
return orig_p;
|
||||||
if (p != orig_p)
|
|
||||||
p->flags |= KPROBE_FLAG_DISABLED;
|
|
||||||
|
|
||||||
/* Try to disarm and disable this/parent probe */
|
/* Disable probe if it is a child probe */
|
||||||
if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
|
if (p != orig_p)
|
||||||
/*
|
p->flags |= KPROBE_FLAG_DISABLED;
|
||||||
* Don't be lazy here. Even if 'kprobes_all_disarmed'
|
|
||||||
* is false, 'orig_p' might not have been armed yet.
|
/* Try to disarm and disable this/parent probe */
|
||||||
* Note arm_all_kprobes() __tries__ to arm all kprobes
|
if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
|
||||||
* on the best effort basis.
|
/*
|
||||||
*/
|
* Don't be lazy here. Even if 'kprobes_all_disarmed'
|
||||||
if (!kprobes_all_disarmed && !kprobe_disabled(orig_p)) {
|
* is false, 'orig_p' might not have been armed yet.
|
||||||
ret = disarm_kprobe(orig_p, true);
|
* Note arm_all_kprobes() __tries__ to arm all kprobes
|
||||||
if (ret) {
|
* on the best effort basis.
|
||||||
p->flags &= ~KPROBE_FLAG_DISABLED;
|
*/
|
||||||
return ERR_PTR(ret);
|
if (!kprobes_all_disarmed && !kprobe_disabled(orig_p)) {
|
||||||
}
|
ret = disarm_kprobe(orig_p, true);
|
||||||
|
if (ret) {
|
||||||
|
p->flags &= ~KPROBE_FLAG_DISABLED;
|
||||||
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
orig_p->flags |= KPROBE_FLAG_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
orig_p->flags |= KPROBE_FLAG_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return orig_p;
|
return orig_p;
|
||||||
|
Loading…
Reference in New Issue
Block a user