Commit eab5cc1e authored by Prasanna S. Panchamukhi's avatar Prasanna S. Panchamukhi Committed by Linus Torvalds

[PATCH] kprobes: x86_64 memory allocation changes

Minor changes to the kprobes code to provide memory allocation for x86_64
architecture outside kprobes spin lock.
Signed-off-by: default avatarPrasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 95e5e682
......@@ -62,10 +62,14 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
int arch_prepare_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
return 0;
}
void arch_copy_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
}
void arch_remove_kprobe(struct kprobe *p)
{
}
......
......@@ -45,13 +45,19 @@ static struct pt_regs jprobe_saved_regs;
int arch_prepare_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
if (IS_MTMSRD(p->ainsn.insn[0]) || IS_RFID(p->ainsn.insn[0]))
kprobe_opcode_t insn = *p->addr;
if (IS_MTMSRD(insn) || IS_RFID(insn))
/* cannot put bp on RFID/MTMSRD */
return 1;
return 0;
}
void arch_copy_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
}
void arch_remove_kprobe(struct kprobe *p)
{
}
......
......@@ -39,10 +39,14 @@
*/
int arch_prepare_kprobe(struct kprobe *p)
{
return 0;
}
void arch_copy_kprobe(struct kprobe *p)
{
p->ainsn.insn[0] = *p->addr;
p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
return 0;
}
void arch_remove_kprobe(struct kprobe *p)
......
......@@ -39,6 +39,8 @@
#include <asm/pgtable.h>
#include <asm/kdebug.h>
static DECLARE_MUTEX(kprobe_mutex);
/* kprobe_status settings */
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002
......@@ -75,17 +77,25 @@ static inline int is_IF_modifier(kprobe_opcode_t *insn)
int arch_prepare_kprobe(struct kprobe *p)
{
/* insn: must be on special executable page on x86_64. */
up(&kprobe_mutex);
p->ainsn.insn = get_insn_slot();
down(&kprobe_mutex);
if (!p->ainsn.insn) {
return -ENOMEM;
}
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
return 0;
}
void arch_copy_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
}
void arch_remove_kprobe(struct kprobe *p)
{
up(&kprobe_mutex);
free_insn_slot(p->ainsn.insn);
down(&kprobe_mutex);
}
static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
......@@ -425,12 +435,12 @@ static kprobe_opcode_t *get_insn_slot(void)
}
/* All out of space. Need to allocate a new page. Use slot 0.*/
kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_ATOMIC);
kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
if (!kip) {
return NULL;
}
kip->insns = (kprobe_opcode_t*) __vmalloc(PAGE_SIZE,
GFP_ATOMIC|__GFP_HIGHMEM, __pgprot(__PAGE_KERNEL_EXEC));
GFP_KERNEL|__GFP_HIGHMEM, __pgprot(__PAGE_KERNEL_EXEC));
if (!kip->insns) {
kfree(kip);
return NULL;
......
......@@ -95,6 +95,7 @@ static inline int kprobe_running(void)
}
extern int arch_prepare_kprobe(struct kprobe *p);
extern void arch_copy_kprobe(struct kprobe *p);
extern void arch_remove_kprobe(struct kprobe *p);
extern void show_registers(struct pt_regs *regs);
......
......@@ -76,18 +76,19 @@ struct kprobe *get_kprobe(void *addr)
int register_kprobe(struct kprobe *p)
{
int ret = 0;
unsigned long flags;
unsigned long flags = 0;
if ((ret = arch_prepare_kprobe(p)) != 0) {
goto out;
}
spin_lock_irqsave(&kprobe_lock, flags);
INIT_HLIST_NODE(&p->hlist);
if (get_kprobe(p->addr)) {
ret = -EEXIST;
goto out;
}
arch_copy_kprobe(p);
if ((ret = arch_prepare_kprobe(p)) != 0) {
goto out;
}
hlist_add_head(&p->hlist,
&kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
......@@ -97,14 +98,16 @@ int register_kprobe(struct kprobe *p)
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
out:
spin_unlock_irqrestore(&kprobe_lock, flags);
if (ret == -EEXIST)
arch_remove_kprobe(p);
return ret;
}
void unregister_kprobe(struct kprobe *p)
{
unsigned long flags;
spin_lock_irqsave(&kprobe_lock, flags);
arch_remove_kprobe(p);
spin_lock_irqsave(&kprobe_lock, flags);
*p->addr = p->opcode;
hlist_del(&p->hlist);
flush_icache_range((unsigned long) p->addr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment