uprobes: Kill set_orig_insn()->is_swbp_at_addr()
Unlike set_swbp(), set_orig_insn()->is_swbp_at_addr() makes sense, although it can't prevent all confusions. But the usage of is_swbp_at_addr() is equally confusing, and it adds the extra get_user_pages() we can avoid. This patch removes set_orig_insn()->is_swbp_at_addr() but changes write_opcode() to do the necessary checks before replace_page(). Perhaps it also makes sense to ensure PAGE_MAPPING_ANON in unregister case. find_active_uprobe() becomes the only user of is_swbp_at_addr(), we can change its semantics. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
This commit is contained in:
Родитель
cceb55aab7
Коммит
ed6f6a50dc
|
@ -190,6 +190,25 @@ static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
|
||||||
kunmap_atomic(kaddr);
|
kunmap_atomic(kaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *new_opcode)
|
||||||
|
{
|
||||||
|
uprobe_opcode_t old_opcode;
|
||||||
|
bool is_swbp;
|
||||||
|
|
||||||
|
copy_opcode(page, vaddr, &old_opcode);
|
||||||
|
is_swbp = is_swbp_insn(&old_opcode);
|
||||||
|
|
||||||
|
if (is_swbp_insn(new_opcode)) {
|
||||||
|
if (is_swbp) /* register: already installed? */
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (!is_swbp) /* unregister: was it changed by us? */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* Expect the breakpoint instruction to be the smallest size instruction for
|
* Expect the breakpoint instruction to be the smallest size instruction for
|
||||||
|
@ -226,6 +245,10 @@ retry:
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = verify_opcode(old_page, vaddr, &opcode);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto put_old;
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
|
new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
|
||||||
if (!new_page)
|
if (!new_page)
|
||||||
|
@ -311,15 +334,6 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned
|
||||||
int __weak
|
int __weak
|
||||||
set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
|
set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
|
||||||
{
|
{
|
||||||
int result;
|
|
||||||
|
|
||||||
result = is_swbp_at_addr(mm, vaddr);
|
|
||||||
if (!result)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (result != 1)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
|
return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче