设备树编译器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");
}
posted @ 2025-04-10 22:07  xiaobing3314  阅读(40)  评论(0)    收藏  举报