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) |
