Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cceb55aa authored by Oleg Nesterov's avatar Oleg Nesterov
Browse files

uprobes: Introduce copy_opcode(), kill read_opcode()



No functional changes, preparations.

1. Extract the kmap-and-memcpy code from read_opcode() into the
   new trivial helper, copy_opcode(). The next patch will add
   another user.

2. read_opcode() becomes really trivial, fold it into its single
   caller, is_swbp_at_addr().

3. Remove "auprobe" argument from write_opcode(), it is not used
   since f403072c.

Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarSrikar Dronamraju <srikar@linux.vnet.ibm.com>
parent e97f65a1
Loading
Loading
Loading
Loading
+19 −44
Original line number Original line Diff line number Diff line
@@ -183,19 +183,25 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
	return *insn == UPROBE_SWBP_INSN;
	return *insn == UPROBE_SWBP_INSN;
}
}


static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode)
{
	void *kaddr = kmap_atomic(page);
	memcpy(opcode, kaddr + (vaddr & ~PAGE_MASK), UPROBE_SWBP_INSN_SIZE);
	kunmap_atomic(kaddr);
}

/*
/*
 * NOTE:
 * NOTE:
 * Expect the breakpoint instruction to be the smallest size instruction for
 * Expect the breakpoint instruction to be the smallest size instruction for
 * the architecture. If an arch has variable length instruction and the
 * the architecture. If an arch has variable length instruction and the
 * breakpoint instruction is not of the smallest length instruction
 * breakpoint instruction is not of the smallest length instruction
 * supported by that architecture then we need to modify read_opcode /
 * supported by that architecture then we need to modify is_swbp_at_addr and
 * write_opcode accordingly. This would never be a problem for archs that
 * write_opcode accordingly. This would never be a problem for archs that
 * have fixed length instructions.
 * have fixed length instructions.
 */
 */


/*
/*
 * write_opcode - write the opcode at a given virtual address.
 * write_opcode - write the opcode at a given virtual address.
 * @auprobe: arch breakpointing information.
 * @mm: the probed process address space.
 * @mm: the probed process address space.
 * @vaddr: the virtual address to store the opcode.
 * @vaddr: the virtual address to store the opcode.
 * @opcode: opcode to be written at @vaddr.
 * @opcode: opcode to be written at @vaddr.
@@ -206,8 +212,8 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
 * For mm @mm, write the opcode at @vaddr.
 * For mm @mm, write the opcode at @vaddr.
 * Return 0 (success) or a negative errno.
 * Return 0 (success) or a negative errno.
 */
 */
static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
static int write_opcode(struct mm_struct *mm, unsigned long vaddr,
			unsigned long vaddr, uprobe_opcode_t opcode)
			uprobe_opcode_t opcode)
{
{
	struct page *old_page, *new_page;
	struct page *old_page, *new_page;
	void *vaddr_old, *vaddr_new;
	void *vaddr_old, *vaddr_new;
@@ -253,40 +259,9 @@ put_old:
	return ret;
	return ret;
}
}


/**
 * read_opcode - read the opcode at a given virtual address.
 * @mm: the probed process address space.
 * @vaddr: the virtual address to read the opcode.
 * @opcode: location to store the read opcode.
 *
 * Called with mm->mmap_sem held (for read and with a reference to
 * mm.
 *
 * For mm @mm, read the opcode at @vaddr and store it in @opcode.
 * Return 0 (success) or a negative errno.
 */
static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode)
{
	struct page *page;
	void *vaddr_new;
	int ret;

	ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
	if (ret <= 0)
		return ret;

	vaddr_new = kmap_atomic(page);
	vaddr &= ~PAGE_MASK;
	memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE);
	kunmap_atomic(vaddr_new);

	put_page(page);

	return 0;
}

static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
{
{
	struct page *page;
	uprobe_opcode_t opcode;
	uprobe_opcode_t opcode;
	int result;
	int result;


@@ -300,14 +275,14 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
			goto out;
			goto out;
	}
	}


	result = read_opcode(mm, vaddr, &opcode);
	result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
	if (result)
	if (result < 0)
		return result;
		return result;
out:
	if (is_swbp_insn(&opcode))
		return 1;


	return 0;
	copy_opcode(page, vaddr, &opcode);
	put_page(page);
 out:
	return is_swbp_insn(&opcode);
}
}


/**
/**
@@ -321,7 +296,7 @@ out:
 */
 */
int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
{
{
	return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN);
	return write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
}
}


/**
/**
@@ -345,7 +320,7 @@ set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long v
	if (result != 1)
	if (result != 1)
		return result;
		return result;


	return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
	return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
}
}


static int match_uprobe(struct uprobe *l, struct uprobe *r)
static int match_uprobe(struct uprobe *l, struct uprobe *r)