diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-09-23 15:10:18 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2012-09-29 15:21:54 -0400 |
commit | cceb55aab73d2aea8f4d6f7414d2e1b647a3dacb (patch) | |
tree | 3da300ea711b72be0d5dc846d65f94695c5a7ed5 /kernel | |
parent | e97f65a17deafacc360a4cb75ae944897ecea6d7 (diff) |
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 f403072c6.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/uprobes.c | 63 |
1 files changed, 19 insertions, 44 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index a4453d1c8199..b6f0f716a884 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -183,19 +183,25 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn) | |||
183 | return *insn == UPROBE_SWBP_INSN; | 183 | return *insn == UPROBE_SWBP_INSN; |
184 | } | 184 | } |
185 | 185 | ||
186 | static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode) | ||
187 | { | ||
188 | void *kaddr = kmap_atomic(page); | ||
189 | memcpy(opcode, kaddr + (vaddr & ~PAGE_MASK), UPROBE_SWBP_INSN_SIZE); | ||
190 | kunmap_atomic(kaddr); | ||
191 | } | ||
192 | |||
186 | /* | 193 | /* |
187 | * NOTE: | 194 | * NOTE: |
188 | * Expect the breakpoint instruction to be the smallest size instruction for | 195 | * Expect the breakpoint instruction to be the smallest size instruction for |
189 | * the architecture. If an arch has variable length instruction and the | 196 | * the architecture. If an arch has variable length instruction and the |
190 | * breakpoint instruction is not of the smallest length instruction | 197 | * breakpoint instruction is not of the smallest length instruction |
191 | * supported by that architecture then we need to modify read_opcode / | 198 | * supported by that architecture then we need to modify is_swbp_at_addr and |
192 | * write_opcode accordingly. This would never be a problem for archs that | 199 | * write_opcode accordingly. This would never be a problem for archs that |
193 | * have fixed length instructions. | 200 | * have fixed length instructions. |
194 | */ | 201 | */ |
195 | 202 | ||
196 | /* | 203 | /* |
197 | * write_opcode - write the opcode at a given virtual address. | 204 | * write_opcode - write the opcode at a given virtual address. |
198 | * @auprobe: arch breakpointing information. | ||
199 | * @mm: the probed process address space. | 205 | * @mm: the probed process address space. |
200 | * @vaddr: the virtual address to store the opcode. | 206 | * @vaddr: the virtual address to store the opcode. |
201 | * @opcode: opcode to be written at @vaddr. | 207 | * @opcode: opcode to be written at @vaddr. |
@@ -206,8 +212,8 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn) | |||
206 | * For mm @mm, write the opcode at @vaddr. | 212 | * For mm @mm, write the opcode at @vaddr. |
207 | * Return 0 (success) or a negative errno. | 213 | * Return 0 (success) or a negative errno. |
208 | */ | 214 | */ |
209 | static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, | 215 | static int write_opcode(struct mm_struct *mm, unsigned long vaddr, |
210 | unsigned long vaddr, uprobe_opcode_t opcode) | 216 | uprobe_opcode_t opcode) |
211 | { | 217 | { |
212 | struct page *old_page, *new_page; | 218 | struct page *old_page, *new_page; |
213 | void *vaddr_old, *vaddr_new; | 219 | void *vaddr_old, *vaddr_new; |
@@ -253,40 +259,9 @@ put_old: | |||
253 | return ret; | 259 | return ret; |
254 | } | 260 | } |
255 | 261 | ||
256 | /** | ||
257 | * read_opcode - read the opcode at a given virtual address. | ||
258 | * @mm: the probed process address space. | ||
259 | * @vaddr: the virtual address to read the opcode. | ||
260 | * @opcode: location to store the read opcode. | ||
261 | * | ||
262 | * Called with mm->mmap_sem held (for read and with a reference to | ||
263 | * mm. | ||
264 | * | ||
265 | * For mm @mm, read the opcode at @vaddr and store it in @opcode. | ||
266 | * Return 0 (success) or a negative errno. | ||
267 | */ | ||
268 | static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode) | ||
269 | { | ||
270 | struct page *page; | ||
271 | void *vaddr_new; | ||
272 | int ret; | ||
273 | |||
274 | ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); | ||
275 | if (ret <= 0) | ||
276 | return ret; | ||
277 | |||
278 | vaddr_new = kmap_atomic(page); | ||
279 | vaddr &= ~PAGE_MASK; | ||
280 | memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE); | ||
281 | kunmap_atomic(vaddr_new); | ||
282 | |||
283 | put_page(page); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | 262 | static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) |
289 | { | 263 | { |
264 | struct page *page; | ||
290 | uprobe_opcode_t opcode; | 265 | uprobe_opcode_t opcode; |
291 | int result; | 266 | int result; |
292 | 267 | ||
@@ -300,14 +275,14 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | |||
300 | goto out; | 275 | goto out; |
301 | } | 276 | } |
302 | 277 | ||
303 | result = read_opcode(mm, vaddr, &opcode); | 278 | result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); |
304 | if (result) | 279 | if (result < 0) |
305 | return result; | 280 | return result; |
306 | out: | ||
307 | if (is_swbp_insn(&opcode)) | ||
308 | return 1; | ||
309 | 281 | ||
310 | return 0; | 282 | copy_opcode(page, vaddr, &opcode); |
283 | put_page(page); | ||
284 | out: | ||
285 | return is_swbp_insn(&opcode); | ||
311 | } | 286 | } |
312 | 287 | ||
313 | /** | 288 | /** |
@@ -321,7 +296,7 @@ out: | |||
321 | */ | 296 | */ |
322 | int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) | 297 | int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) |
323 | { | 298 | { |
324 | return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); | 299 | return write_opcode(mm, vaddr, UPROBE_SWBP_INSN); |
325 | } | 300 | } |
326 | 301 | ||
327 | /** | 302 | /** |
@@ -345,7 +320,7 @@ set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long v | |||
345 | if (result != 1) | 320 | if (result != 1) |
346 | return result; | 321 | return result; |
347 | 322 | ||
348 | return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); | 323 | return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); |
349 | } | 324 | } |
350 | 325 | ||
351 | static int match_uprobe(struct uprobe *l, struct uprobe *r) | 326 | static int match_uprobe(struct uprobe *l, struct uprobe *r) |