diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-01-05 06:29:18 -0500 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2015-01-09 04:36:51 -0500 |
commit | 83803d97dae1eaf6850a45ef8ee179cc66e147dc (patch) | |
tree | e2b1124f1c7896dcadb2af471a0570b019dad551 /arch/arm/probes/decode.c | |
parent | 832607e79d7423c67ef8a3de8dfa3d25b5b0bf86 (diff) |
ARM: kprobes: introduces checker
This patch introdces 'checker' to decoding phase, and calls checkers
when instruction decoding. This allows further decoding for specific
instructions. This patch introduces a stub call of checkers in kprobe
arch_prepare_kprobe() as an example and for further expansion.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Reviewed-by: Jon Medhurst <tixy@linaro.org>
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Jon Medhurst <tixy@linaro.org>
Diffstat (limited to 'arch/arm/probes/decode.c')
-rw-r--r-- | arch/arm/probes/decode.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c index 3b05d5742359..c7d442018902 100644 --- a/arch/arm/probes/decode.c +++ b/arch/arm/probes/decode.c | |||
@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { | |||
342 | [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) | 342 | [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) |
343 | }; | 343 | }; |
344 | 344 | ||
345 | static int run_checkers(const struct decode_checker *checkers[], | ||
346 | int action, probes_opcode_t insn, | ||
347 | struct arch_probes_insn *asi, | ||
348 | const struct decode_header *h) | ||
349 | { | ||
350 | const struct decode_checker **p; | ||
351 | |||
352 | if (!checkers) | ||
353 | return INSN_GOOD; | ||
354 | |||
355 | p = checkers; | ||
356 | while (*p != NULL) { | ||
357 | int retval; | ||
358 | probes_check_t *checker_func = (*p)[action].checker; | ||
359 | |||
360 | retval = INSN_GOOD; | ||
361 | if (checker_func) | ||
362 | retval = checker_func(insn, asi, h); | ||
363 | if (retval == INSN_REJECTED) | ||
364 | return retval; | ||
365 | p++; | ||
366 | } | ||
367 | return INSN_GOOD; | ||
368 | } | ||
369 | |||
345 | /* | 370 | /* |
346 | * probes_decode_insn operates on data tables in order to decode an ARM | 371 | * probes_decode_insn operates on data tables in order to decode an ARM |
347 | * architecture instruction onto which a kprobe has been placed. | 372 | * architecture instruction onto which a kprobe has been placed. |
@@ -388,11 +413,17 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { | |||
388 | int __kprobes | 413 | int __kprobes |
389 | probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 414 | probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
390 | const union decode_item *table, bool thumb, | 415 | const union decode_item *table, bool thumb, |
391 | bool emulate, const union decode_action *actions) | 416 | bool emulate, const union decode_action *actions, |
417 | const struct decode_checker *checkers[]) | ||
392 | { | 418 | { |
393 | const struct decode_header *h = (struct decode_header *)table; | 419 | const struct decode_header *h = (struct decode_header *)table; |
394 | const struct decode_header *next; | 420 | const struct decode_header *next; |
395 | bool matched = false; | 421 | bool matched = false; |
422 | /* | ||
423 | * @insn can be modified by decode_regs. Save its original | ||
424 | * value for checkers. | ||
425 | */ | ||
426 | probes_opcode_t origin_insn = insn; | ||
396 | 427 | ||
397 | if (emulate) | 428 | if (emulate) |
398 | insn = prepare_emulated_insn(insn, asi, thumb); | 429 | insn = prepare_emulated_insn(insn, asi, thumb); |
@@ -422,24 +453,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | |||
422 | } | 453 | } |
423 | 454 | ||
424 | case DECODE_TYPE_CUSTOM: { | 455 | case DECODE_TYPE_CUSTOM: { |
456 | int err; | ||
425 | struct decode_custom *d = (struct decode_custom *)h; | 457 | struct decode_custom *d = (struct decode_custom *)h; |
426 | return actions[d->decoder.action].decoder(insn, asi, h); | 458 | int action = d->decoder.action; |
459 | |||
460 | err = run_checkers(checkers, action, origin_insn, asi, h); | ||
461 | if (err == INSN_REJECTED) | ||
462 | return INSN_REJECTED; | ||
463 | return actions[action].decoder(insn, asi, h); | ||
427 | } | 464 | } |
428 | 465 | ||
429 | case DECODE_TYPE_SIMULATE: { | 466 | case DECODE_TYPE_SIMULATE: { |
467 | int err; | ||
430 | struct decode_simulate *d = (struct decode_simulate *)h; | 468 | struct decode_simulate *d = (struct decode_simulate *)h; |
431 | asi->insn_handler = actions[d->handler.action].handler; | 469 | int action = d->handler.action; |
470 | |||
471 | err = run_checkers(checkers, action, origin_insn, asi, h); | ||
472 | if (err == INSN_REJECTED) | ||
473 | return INSN_REJECTED; | ||
474 | asi->insn_handler = actions[action].handler; | ||
432 | return INSN_GOOD_NO_SLOT; | 475 | return INSN_GOOD_NO_SLOT; |
433 | } | 476 | } |
434 | 477 | ||
435 | case DECODE_TYPE_EMULATE: { | 478 | case DECODE_TYPE_EMULATE: { |
479 | int err; | ||
436 | struct decode_emulate *d = (struct decode_emulate *)h; | 480 | struct decode_emulate *d = (struct decode_emulate *)h; |
481 | int action = d->handler.action; | ||
482 | |||
483 | err = run_checkers(checkers, action, origin_insn, asi, h); | ||
484 | if (err == INSN_REJECTED) | ||
485 | return INSN_REJECTED; | ||
437 | 486 | ||
438 | if (!emulate) | 487 | if (!emulate) |
439 | return actions[d->handler.action].decoder(insn, | 488 | return actions[action].decoder(insn, asi, h); |
440 | asi, h); | ||
441 | 489 | ||
442 | asi->insn_handler = actions[d->handler.action].handler; | 490 | asi->insn_handler = actions[action].handler; |
443 | set_emulated_insn(insn, asi, thumb); | 491 | set_emulated_insn(insn, asi, thumb); |
444 | return INSN_GOOD; | 492 | return INSN_GOOD; |
445 | } | 493 | } |