设备树编译器DTC的编译过程中告警错误检查
1、告警错误检查数据结构
1.1 检查状态的枚举结构
enum checkstatus {
UNCHECKED = 0,
PREREQ,
PASSED,
FAILED,
};
1.2 检查调用函数指针
typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node);
1.3 检查结构体
struct check {
const char *name;
check_fn fn;
void *data;
bool warn, error;
enum checkstatus status;
bool inprogress;
int num_prereqs;
struct check **prereq;
};
1.4 检查项宏定义
#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...) \
static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \
static struct check nm_ = { \
.name = #nm_, \
.fn = (fn_), \
.data = (d_), \
.warn = (w_), \
.error = (e_), \
.status = UNCHECKED, \
.num_prereqs = ARRAY_SIZE(nm_##_prereqs), \
.prereq = nm_##_prereqs, \
};
1.5 告警,错误,和检查项宏定义
#define WARNING(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__)
#define ERROR(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__)
#define CHECK(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__)
2、失败检查宏定义
#define FAIL(c, dti, node, ...) \
do { \
TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
(c)->status = FAILED; \
check_msg((c), dti, node, NULL, __VA_ARGS__); \
} while (0)
#define FAIL_PROP(c, dti, node, prop, ...) \
do { \
TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
(c)->status = FAILED; \
check_msg((c), dti, node, prop, __VA_ARGS__); \
} while (0)
3、运行检查的流程
void process_checks(bool force, struct dt_info *dti)
{
unsigned int i;
int error = 0;
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
struct check *c = check_table[i];
if (c->warn || c->error)
error = error || run_check(c, dti);
}
if (error) {
if (!force) {
fprintf(stderr, "ERROR: Input tree has errors, aborting "
"(use -f to force output)\n");
exit(2);
} else if (quiet < 3) {
fprintf(stderr, "Warning: Input tree has errors, "
"output forced\n");
}
}
}
函数的for循环中,循环每次需要检查的项。每种类型的检查项在设计完成检查函数后,使用宏定义声明,如下检查属性的值是否是字符串的例子:
static void check_is_string(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
char *propname = c->data;
prop = get_property(node, propname);
if (!prop)
return; /* Not present, assumed ok */
if (!data_is_one_string(prop->val))
FAIL_PROP(c, dti, node, prop, "property is not a string");
}
这里有两种宏定义声明,一个是产生告警的,一个是产生错误的,如下:
#define WARNING_IF_NOT_STRING(nm, propname) \
WARNING(nm, check_is_string, (propname))
#define ERROR_IF_NOT_STRING(nm, propname) \
ERROR(nm, check_is_string, (propname))
在语法中有检查设备类型是否是字符串,标签是否是字符串类型的,如下是要检查的具体的项是否是字符串的宏定义声明,如下:
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
WARNING_IF_NOT_STRING(model_is_string, "model");
WARNING_IF_NOT_STRING(status_is_string, "status");
WARNING_IF_NOT_STRING(label_is_string, "label");
struct check *check_table[] ={ &device_type_is_string,&model_is_string, &status_is_string,&label_is_string,}
然后调用run_check(c, dti);函数,它做如下的调用:
static bool run_check(struct check *c, struct dt_info *dti)
{
struct node *dt = dti->dt;
bool error = false;
int i;
assert(!c->inprogress);
if (c->status != UNCHECKED)
goto out;
c->inprogress = true;
for (i = 0; i < c->num_prereqs; i++) {
struct check *prq = c->prereq[i];
error = error || run_check(prq, dti);
if (prq->status != PASSED) {
c->status = PREREQ;
check_msg(c, dti, NULL, NULL, "Failed prerequisite '%s'",
c->prereq[i]->name);
}
}
if (c->status != UNCHECKED)
goto out;
check_nodes_props(c, dti, dt);
if (c->status == UNCHECKED)
c->status = PASSED;
TRACE(c, "\tCompleted, status %d", c->status);
out:
c->inprogress = false;
if ((c->status != PASSED) && (c->error))
error = true;
return error;
}
static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
{
struct node *child;
TRACE(c, "%s", node->fullpath);
if (c->fn)
c->fn(c, dti, node);
for_each_child(node, child)
check_nodes_props(c, dti, child);
}
上面函数,最终会调用
if (c->fn)
c->fn(c, dti, node);
运行check结构体提前注册的函数指针,调用具体的实现函数。
如,检查是否是字符串是,会调用下面函数:
static void check_is_string(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
char *propname = c->data;
prop = get_property(node, propname);
if (!prop)
return; /* Not present, assumed ok */
if (!data_is_one_string(prop->val))
FAIL_PROP(c, dti, node, prop, "property is not a string");
}