ARM: kprobes: Add decoding table self-consistency tests
These check that the bitmask and match value used in the decoding tables are self consistent. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
This commit is contained in:
parent
2c89240b63
commit
68f360e753
|
@ -442,6 +442,92 @@ static int run_api_tests(long (*func)(long, long))
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decoding table self-consistency tests
|
||||
*/
|
||||
|
||||
static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
|
||||
[DECODE_TYPE_TABLE] = sizeof(struct decode_table),
|
||||
[DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom),
|
||||
[DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate),
|
||||
[DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate),
|
||||
[DECODE_TYPE_OR] = sizeof(struct decode_or),
|
||||
[DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
|
||||
};
|
||||
|
||||
static int table_iter(const union decode_item *table,
|
||||
int (*fn)(const struct decode_header *, void *),
|
||||
void *args)
|
||||
{
|
||||
const struct decode_header *h = (struct decode_header *)table;
|
||||
int result;
|
||||
|
||||
for (;;) {
|
||||
enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
|
||||
|
||||
if (type == DECODE_TYPE_END)
|
||||
return 0;
|
||||
|
||||
result = fn(h, args);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
h = (struct decode_header *)
|
||||
((uintptr_t)h + decode_struct_sizes[type]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int table_test_fail(const struct decode_header *h, const char* message)
|
||||
{
|
||||
|
||||
pr_err("FAIL: kprobes test failure \"%s\" (mask %08x, value %08x)\n",
|
||||
message, h->mask.bits, h->value.bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct table_test_args {
|
||||
const union decode_item *root_table;
|
||||
u32 parent_mask;
|
||||
u32 parent_value;
|
||||
};
|
||||
|
||||
static int table_test_fn(const struct decode_header *h, void *args)
|
||||
{
|
||||
struct table_test_args *a = (struct table_test_args *)args;
|
||||
enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
|
||||
|
||||
if (h->value.bits & ~h->mask.bits)
|
||||
return table_test_fail(h, "Match value has bits not in mask");
|
||||
|
||||
if ((h->mask.bits & a->parent_mask) != a->parent_mask)
|
||||
return table_test_fail(h, "Mask has bits not in parent mask");
|
||||
|
||||
if ((h->value.bits ^ a->parent_value) & a->parent_mask)
|
||||
return table_test_fail(h, "Value is inconsistent with parent");
|
||||
|
||||
if (type == DECODE_TYPE_TABLE) {
|
||||
struct decode_table *d = (struct decode_table *)h;
|
||||
struct table_test_args args2 = *a;
|
||||
args2.parent_mask = h->mask.bits;
|
||||
args2.parent_value = h->value.bits;
|
||||
return table_iter(d->table.table, table_test_fn, &args2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int table_test(const union decode_item *table)
|
||||
{
|
||||
struct table_test_args args = {
|
||||
.root_table = table,
|
||||
.parent_mask = 0,
|
||||
.parent_value = 0
|
||||
};
|
||||
return table_iter(args.root_table, table_test_fn, &args);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Framework for instruction set test cases
|
||||
*/
|
||||
|
@ -1117,8 +1203,15 @@ end:
|
|||
* Top level test functions
|
||||
*/
|
||||
|
||||
static int run_test_cases(void (*tests)(void))
|
||||
static int run_test_cases(void (*tests)(void), const union decode_item *table)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_info(" Check decoding tables\n");
|
||||
ret = table_test(table);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_info(" Run test cases\n");
|
||||
tests();
|
||||
|
||||
|
@ -1140,7 +1233,7 @@ static int __init run_all_tests(void)
|
|||
goto out;
|
||||
|
||||
pr_info("ARM instruction simulation\n");
|
||||
ret = run_test_cases(kprobe_arm_test_cases);
|
||||
ret = run_test_cases(kprobe_arm_test_cases, kprobe_decode_arm_table);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -1162,12 +1255,14 @@ static int __init run_all_tests(void)
|
|||
goto out;
|
||||
|
||||
pr_info("16-bit Thumb instruction simulation\n");
|
||||
ret = run_test_cases(kprobe_thumb16_test_cases);
|
||||
ret = run_test_cases(kprobe_thumb16_test_cases,
|
||||
kprobe_decode_thumb16_table);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
pr_info("32-bit Thumb instruction simulation\n");
|
||||
ret = run_test_cases(kprobe_thumb32_test_cases);
|
||||
ret = run_test_cases(kprobe_thumb32_test_cases,
|
||||
kprobe_decode_thumb32_table);
|
||||
if (ret)
|
||||
goto out;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue