diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-08-28 11:38:35 -0400 |
---|---|---|
committer | Jon Medhurst <tixy@yxit.co.uk> | 2011-09-20 14:17:44 -0400 |
commit | 963780dfe390e80e148eb84f0c84a01533a64d28 (patch) | |
tree | f89638b13a62b240886bc9363f857df6c8d4b290 /arch | |
parent | 68f360e753668b61366b7b4b2a5aa77ac5157c37 (diff) |
ARM: kprobes: Add decoding table test coverage analysis
This is used to verify that all combinations of CPU instructions
described by the kprobes decoding tables have a test case.
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/kprobes-test.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 6c0946c023f8..fe169e934d42 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c | |||
@@ -178,6 +178,7 @@ | |||
178 | 178 | ||
179 | #include <linux/kernel.h> | 179 | #include <linux/kernel.h> |
180 | #include <linux/module.h> | 180 | #include <linux/module.h> |
181 | #include <linux/slab.h> | ||
181 | #include <linux/kprobes.h> | 182 | #include <linux/kprobes.h> |
182 | 183 | ||
183 | #include "kprobes.h" | 184 | #include "kprobes.h" |
@@ -529,6 +530,250 @@ static int table_test(const union decode_item *table) | |||
529 | 530 | ||
530 | 531 | ||
531 | /* | 532 | /* |
533 | * Decoding table test coverage analysis | ||
534 | * | ||
535 | * coverage_start() builds a coverage_table which contains a list of | ||
536 | * coverage_entry's to match each entry in the specified kprobes instruction | ||
537 | * decoding table. | ||
538 | * | ||
539 | * When test cases are run, coverage_add() is called to process each case. | ||
540 | * This looks up the corresponding entry in the coverage_table and sets it as | ||
541 | * being matched, as well as clearing the regs flag appropriate for the test. | ||
542 | * | ||
543 | * After all test cases have been run, coverage_end() is called to check that | ||
544 | * all entries in coverage_table have been matched and that all regs flags are | ||
545 | * cleared. I.e. that all possible combinations of instructions described by | ||
546 | * the kprobes decoding tables have had a test case executed for them. | ||
547 | */ | ||
548 | |||
549 | bool coverage_fail; | ||
550 | |||
551 | #define MAX_COVERAGE_ENTRIES 256 | ||
552 | |||
553 | struct coverage_entry { | ||
554 | const struct decode_header *header; | ||
555 | unsigned regs; | ||
556 | unsigned nesting; | ||
557 | char matched; | ||
558 | }; | ||
559 | |||
560 | struct coverage_table { | ||
561 | struct coverage_entry *base; | ||
562 | unsigned num_entries; | ||
563 | unsigned nesting; | ||
564 | }; | ||
565 | |||
566 | struct coverage_table coverage; | ||
567 | |||
568 | #define COVERAGE_ANY_REG (1<<0) | ||
569 | #define COVERAGE_SP (1<<1) | ||
570 | #define COVERAGE_PC (1<<2) | ||
571 | #define COVERAGE_PCWB (1<<3) | ||
572 | |||
573 | static const char coverage_register_lookup[16] = { | ||
574 | [REG_TYPE_ANY] = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC, | ||
575 | [REG_TYPE_SAMEAS16] = COVERAGE_ANY_REG, | ||
576 | [REG_TYPE_SP] = COVERAGE_SP, | ||
577 | [REG_TYPE_PC] = COVERAGE_PC, | ||
578 | [REG_TYPE_NOSP] = COVERAGE_ANY_REG | COVERAGE_SP, | ||
579 | [REG_TYPE_NOSPPC] = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC, | ||
580 | [REG_TYPE_NOPC] = COVERAGE_ANY_REG | COVERAGE_PC, | ||
581 | [REG_TYPE_NOPCWB] = COVERAGE_ANY_REG | COVERAGE_PC | COVERAGE_PCWB, | ||
582 | [REG_TYPE_NOPCX] = COVERAGE_ANY_REG, | ||
583 | [REG_TYPE_NOSPPCX] = COVERAGE_ANY_REG | COVERAGE_SP, | ||
584 | }; | ||
585 | |||
586 | unsigned coverage_start_registers(const struct decode_header *h) | ||
587 | { | ||
588 | unsigned regs = 0; | ||
589 | int i; | ||
590 | for (i = 0; i < 20; i += 4) { | ||
591 | int r = (h->type_regs.bits >> (DECODE_TYPE_BITS + i)) & 0xf; | ||
592 | regs |= coverage_register_lookup[r] << i; | ||
593 | } | ||
594 | return regs; | ||
595 | } | ||
596 | |||
597 | static int coverage_start_fn(const struct decode_header *h, void *args) | ||
598 | { | ||
599 | struct coverage_table *coverage = (struct coverage_table *)args; | ||
600 | enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; | ||
601 | struct coverage_entry *entry = coverage->base + coverage->num_entries; | ||
602 | |||
603 | if (coverage->num_entries == MAX_COVERAGE_ENTRIES - 1) { | ||
604 | pr_err("FAIL: Out of space for test coverage data"); | ||
605 | return -ENOMEM; | ||
606 | } | ||
607 | |||
608 | ++coverage->num_entries; | ||
609 | |||
610 | entry->header = h; | ||
611 | entry->regs = coverage_start_registers(h); | ||
612 | entry->nesting = coverage->nesting; | ||
613 | entry->matched = false; | ||
614 | |||
615 | if (type == DECODE_TYPE_TABLE) { | ||
616 | struct decode_table *d = (struct decode_table *)h; | ||
617 | int ret; | ||
618 | ++coverage->nesting; | ||
619 | ret = table_iter(d->table.table, coverage_start_fn, coverage); | ||
620 | --coverage->nesting; | ||
621 | return ret; | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static int coverage_start(const union decode_item *table) | ||
628 | { | ||
629 | coverage.base = kmalloc(MAX_COVERAGE_ENTRIES * | ||
630 | sizeof(struct coverage_entry), GFP_KERNEL); | ||
631 | coverage.num_entries = 0; | ||
632 | coverage.nesting = 0; | ||
633 | return table_iter(table, coverage_start_fn, &coverage); | ||
634 | } | ||
635 | |||
636 | static void | ||
637 | coverage_add_registers(struct coverage_entry *entry, kprobe_opcode_t insn) | ||
638 | { | ||
639 | int regs = entry->header->type_regs.bits >> DECODE_TYPE_BITS; | ||
640 | int i; | ||
641 | for (i = 0; i < 20; i += 4) { | ||
642 | enum decode_reg_type reg_type = (regs >> i) & 0xf; | ||
643 | int reg = (insn >> i) & 0xf; | ||
644 | int flag; | ||
645 | |||
646 | if (!reg_type) | ||
647 | continue; | ||
648 | |||
649 | if (reg == 13) | ||
650 | flag = COVERAGE_SP; | ||
651 | else if (reg == 15) | ||
652 | flag = COVERAGE_PC; | ||
653 | else | ||
654 | flag = COVERAGE_ANY_REG; | ||
655 | entry->regs &= ~(flag << i); | ||
656 | |||
657 | switch (reg_type) { | ||
658 | |||
659 | case REG_TYPE_NONE: | ||
660 | case REG_TYPE_ANY: | ||
661 | case REG_TYPE_SAMEAS16: | ||
662 | break; | ||
663 | |||
664 | case REG_TYPE_SP: | ||
665 | if (reg != 13) | ||
666 | return; | ||
667 | break; | ||
668 | |||
669 | case REG_TYPE_PC: | ||
670 | if (reg != 15) | ||
671 | return; | ||
672 | break; | ||
673 | |||
674 | case REG_TYPE_NOSP: | ||
675 | if (reg == 13) | ||
676 | return; | ||
677 | break; | ||
678 | |||
679 | case REG_TYPE_NOSPPC: | ||
680 | case REG_TYPE_NOSPPCX: | ||
681 | if (reg == 13 || reg == 15) | ||
682 | return; | ||
683 | break; | ||
684 | |||
685 | case REG_TYPE_NOPCWB: | ||
686 | if (!is_writeback(insn)) | ||
687 | break; | ||
688 | if (reg == 15) { | ||
689 | entry->regs &= ~(COVERAGE_PCWB << i); | ||
690 | return; | ||
691 | } | ||
692 | break; | ||
693 | |||
694 | case REG_TYPE_NOPC: | ||
695 | case REG_TYPE_NOPCX: | ||
696 | if (reg == 15) | ||
697 | return; | ||
698 | break; | ||
699 | } | ||
700 | |||
701 | } | ||
702 | } | ||
703 | |||
704 | static void coverage_add(kprobe_opcode_t insn) | ||
705 | { | ||
706 | struct coverage_entry *entry = coverage.base; | ||
707 | struct coverage_entry *end = coverage.base + coverage.num_entries; | ||
708 | bool matched = false; | ||
709 | unsigned nesting = 0; | ||
710 | |||
711 | for (; entry < end; ++entry) { | ||
712 | const struct decode_header *h = entry->header; | ||
713 | enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; | ||
714 | |||
715 | if (entry->nesting > nesting) | ||
716 | continue; /* Skip sub-table we didn't match */ | ||
717 | |||
718 | if (entry->nesting < nesting) | ||
719 | break; /* End of sub-table we were scanning */ | ||
720 | |||
721 | if (!matched) { | ||
722 | if ((insn & h->mask.bits) != h->value.bits) | ||
723 | continue; | ||
724 | entry->matched = true; | ||
725 | } | ||
726 | |||
727 | switch (type) { | ||
728 | |||
729 | case DECODE_TYPE_TABLE: | ||
730 | ++nesting; | ||
731 | break; | ||
732 | |||
733 | case DECODE_TYPE_CUSTOM: | ||
734 | case DECODE_TYPE_SIMULATE: | ||
735 | case DECODE_TYPE_EMULATE: | ||
736 | coverage_add_registers(entry, insn); | ||
737 | return; | ||
738 | |||
739 | case DECODE_TYPE_OR: | ||
740 | matched = true; | ||
741 | break; | ||
742 | |||
743 | case DECODE_TYPE_REJECT: | ||
744 | default: | ||
745 | return; | ||
746 | } | ||
747 | |||
748 | } | ||
749 | } | ||
750 | |||
751 | static void coverage_end(void) | ||
752 | { | ||
753 | struct coverage_entry *entry = coverage.base; | ||
754 | struct coverage_entry *end = coverage.base + coverage.num_entries; | ||
755 | |||
756 | for (; entry < end; ++entry) { | ||
757 | u32 mask = entry->header->mask.bits; | ||
758 | u32 value = entry->header->value.bits; | ||
759 | |||
760 | if (entry->regs) { | ||
761 | pr_err("FAIL: Register test coverage missing for %08x %08x (%05x)\n", | ||
762 | mask, value, entry->regs); | ||
763 | coverage_fail = true; | ||
764 | } | ||
765 | if (!entry->matched) { | ||
766 | pr_err("FAIL: Test coverage entry missing for %08x %08x\n", | ||
767 | mask, value); | ||
768 | coverage_fail = true; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | kfree(coverage.base); | ||
773 | } | ||
774 | |||
775 | |||
776 | /* | ||
532 | * Framework for instruction set test cases | 777 | * Framework for instruction set test cases |
533 | */ | 778 | */ |
534 | 779 | ||
@@ -1039,6 +1284,8 @@ static uintptr_t __used kprobes_test_case_start(const char *title, void *stack) | |||
1039 | } | 1284 | } |
1040 | } | 1285 | } |
1041 | 1286 | ||
1287 | coverage_add(current_instruction); | ||
1288 | |||
1042 | if (end_arg->flags & ARG_FLAG_UNSUPPORTED) { | 1289 | if (end_arg->flags & ARG_FLAG_UNSUPPORTED) { |
1043 | if (register_test_probe(&test_case_probe) < 0) | 1290 | if (register_test_probe(&test_case_probe) < 0) |
1044 | goto pass; | 1291 | goto pass; |
@@ -1213,8 +1460,13 @@ static int run_test_cases(void (*tests)(void), const union decode_item *table) | |||
1213 | return ret; | 1460 | return ret; |
1214 | 1461 | ||
1215 | pr_info(" Run test cases\n"); | 1462 | pr_info(" Run test cases\n"); |
1463 | ret = coverage_start(table); | ||
1464 | if (ret) | ||
1465 | return ret; | ||
1466 | |||
1216 | tests(); | 1467 | tests(); |
1217 | 1468 | ||
1469 | coverage_end(); | ||
1218 | return 0; | 1470 | return 0; |
1219 | } | 1471 | } |
1220 | 1472 | ||
@@ -1274,6 +1526,15 @@ static int __init run_all_tests(void) | |||
1274 | goto out; | 1526 | goto out; |
1275 | } | 1527 | } |
1276 | 1528 | ||
1529 | #if __LINUX_ARM_ARCH__ >= 7 | ||
1530 | /* We are able to run all test cases so coverage should be complete */ | ||
1531 | if (coverage_fail) { | ||
1532 | pr_err("FAIL: Test coverage checks failed\n"); | ||
1533 | ret = -EINVAL; | ||
1534 | goto out; | ||
1535 | } | ||
1536 | #endif | ||
1537 | |||
1277 | out: | 1538 | out: |
1278 | if (ret == 0) | 1539 | if (ret == 0) |
1279 | pr_info("Finished kprobe tests OK\n"); | 1540 | pr_info("Finished kprobe tests OK\n"); |