From cf7b9c3d15a17c8b74bb37a0f8064aaed65f234d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 12 Sep 2019 10:25:35 +0200 Subject: of: Fix memory hole in of_find_node_by_reproducible_name() of_get_reproducible_name() returns an allocated string, so we must free it. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 838f530f85..22077fa397 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2306,9 +2306,17 @@ struct device_node *of_find_node_by_reproducible_name(struct device_node *from, { struct device_node *np; - of_tree_for_each_node_from(np, from) - if (!of_node_cmp(of_get_reproducible_name(np), name)) + of_tree_for_each_node_from(np, from) { + char *rep = of_get_reproducible_name(np); + int res; + + res = of_node_cmp(rep, name); + + free(rep); + + if (!res) return np; + } return NULL; } -- cgit v1.2.3 From 1187df45bf9e7a780b76587c96c7f6b4696a3f96 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 11 Sep 2019 14:13:45 +0200 Subject: of: add of_diff() of_diff compares two device trees against each other and prints a diff-like result. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++---- include/of.h | 1 + 2 files changed, 132 insertions(+), 10 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 22077fa397..63e0879f06 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1776,24 +1776,21 @@ struct device_node *of_get_child_by_name(const struct device_node *node, } EXPORT_SYMBOL(of_get_child_by_name); -void of_print_nodes(struct device_node *node, int indent) +static void __of_print_nodes(struct device_node *node, int indent, const char *prefix) { struct device_node *n; struct property *p; - int i; if (!node) return; - for (i = 0; i < indent; i++) - printf("\t"); + if (!prefix) + prefix = ""; - printf("%s%s\n", node->name, node->name ? " {" : "{"); + printf("%s%*s%s%s\n", prefix, indent * 8, "", node->name, node->name ? " {" : "{"); list_for_each_entry(p, &node->properties, list) { - for (i = 0; i < indent + 1; i++) - printf("\t"); - printf("%s", p->name); + printf("%s%*s%s", prefix, (indent + 1) * 8, "", p->name); if (p->length) { printf(" = "); of_print_property(of_property_get_value(p), p->length); @@ -1802,12 +1799,136 @@ void of_print_nodes(struct device_node *node, int indent) } list_for_each_entry(n, &node->children, parent_list) { - of_print_nodes(n, indent + 1); + __of_print_nodes(n, indent + 1, prefix); + } + + printf("%s%*s};\n", prefix, indent * 8, ""); +} + +void of_print_nodes(struct device_node *node, int indent) +{ + __of_print_nodes(node, indent, NULL); +} + +static void __of_print_property(struct property *p, int indent) +{ + int i; + + for (i = 0; i < indent; i++) + printf("\t"); + + printf("%s", p->name); + if (p->length) { + printf(" = "); + of_print_property(of_property_get_value(p), p->length); } + printf(";\n"); +} + +static int __of_print_parents(struct device_node *node) +{ + int indent, i; + + if (!node->parent) + return 0; + + indent = __of_print_parents(node->parent); for (i = 0; i < indent; i++) printf("\t"); - printf("};\n"); + + printf("%s {\n", node->name); + + return indent + 1; +} + +static void of_print_parents(struct device_node *node, int *printed) +{ + if (*printed) + return; + + __of_print_parents(node); + + *printed = 1; +} + +static void of_print_close(struct device_node *node, int *printed) +{ + int depth = 0, i, j; + + if (!*printed) + return; + + while ((node = node->parent)) + depth++; + + for (i = depth; i > 0; i--) { + for (j = 0; j + 1 < i; j++) + printf("\t"); + printf("};\n"); + } +} + +/** + * of_diff - compare two device trees against each other + * @a: The first device tree + * @b: The second device tree + * @indent: The initial indentation level when printing + * + * This function compares two device trees against each other and prints + * a diff-like result. + */ +void of_diff(struct device_node *a, struct device_node *b, int indent) +{ + struct property *ap, *bp; + struct device_node *ca, *cb; + int printed = 0; + + list_for_each_entry(ap, &a->properties, list) { + bp = of_find_property(b, ap->name, NULL); + if (!bp) { + of_print_parents(a, &printed); + printf("- "); + __of_print_property(ap, indent); + continue; + } + + if (ap->length != bp->length || memcmp(of_property_get_value(ap), of_property_get_value(bp), bp->length)) { + of_print_parents(a, &printed); + printf("- "); + __of_print_property(ap, indent); + printf("+ "); + __of_print_property(bp, indent); + } + } + + list_for_each_entry(bp, &b->properties, list) { + ap = of_find_property(a, bp->name, NULL); + if (!ap) { + of_print_parents(a, &printed); + printf("+ "); + __of_print_property(bp, indent); + } + } + + for_each_child_of_node(a, ca) { + cb = of_get_child_by_name(b, ca->name); + if (cb) { + of_diff(ca, cb, indent + 1); + } else { + of_print_parents(a, &printed); + __of_print_nodes(ca, indent, "-"); + } + } + + for_each_child_of_node(b, cb) { + if (!of_get_child_by_name(a, cb->name)) { + of_print_parents(a, &printed); + __of_print_nodes(cb, indent, "+"); + } + } + + of_print_close(a, &printed); } struct device_node *of_new_node(struct device_node *parent, const char *name) diff --git a/include/of.h b/include/of.h index b5f54dd4e5..c8275e169b 100644 --- a/include/of.h +++ b/include/of.h @@ -104,6 +104,7 @@ void of_print_property(const void *data, int len); void of_print_cmdline(struct device_node *root); void of_print_nodes(struct device_node *node, int indent); +void of_diff(struct device_node *a, struct device_node *b, int indent); int of_probe(void); int of_parse_dtb(struct fdt_header *fdt); struct device_node *of_unflatten_dtb(const void *fdt); -- cgit v1.2.3 From 8c767c227d38954a736f55e33b119786f1d740b1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 12 Sep 2019 10:24:42 +0200 Subject: add of_diff command The of_diff command compares two device trees against each other and prints a diff-like result. This can be handy to find out the differences between the barebox live tree and the one we start the kernel with. Another usecase would be to examine the changes our of_fixup process introduces (of_diff - +) Signed-off-by: Sascha Hauer --- commands/Kconfig | 7 ++++ commands/Makefile | 1 + commands/of_diff.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 commands/of_diff.c diff --git a/commands/Kconfig b/commands/Kconfig index e03110fd46..24fd47b5cd 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -2012,6 +2012,13 @@ config CMD_LSMOD help List loaded barebox modules. +config CMD_OF_DIFF + tristate + select OFTREE + prompt "of_diff" + help + Compare two device tree files against each other. + config CMD_OF_DUMP tristate select OFTREE diff --git a/commands/Makefile b/commands/Makefile index 5cd35b78a7..a619ee5765 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o obj-$(CONFIG_CMD_USB) += usb.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_OFTREE) += oftree.o +obj-$(CONFIG_CMD_OF_DIFF) += of_diff.o obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o obj-$(CONFIG_CMD_OF_NODE) += of_node.o obj-$(CONFIG_CMD_OF_DUMP) += of_dump.o diff --git a/commands/of_diff.c b/commands/of_diff.c new file mode 100644 index 0000000000..8ef006dea8 --- /dev/null +++ b/commands/of_diff.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * of_diff.c - compare device tree files + * + * Copyright (c) 2019 Sascha Hauer , Pengutronix + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_node *get_tree(const char *filename, struct device_node *root) +{ + struct device_node *node; + void *fdt; + size_t size; + int ret; + + if (!strcmp(filename, "-")) { + node = of_get_root_node(); + if (!node) + return ERR_PTR(-ENOENT); + + return of_copy_node(NULL, node); + } + + if (!strcmp(filename, "+")) { + node = of_get_root_node(); + if (!node) + return ERR_PTR(-ENOENT); + + node = of_copy_node(NULL, root); + + of_fix_tree(node); + + return node; + } + + ret = read_file_2(filename, &size, &fdt, FILESIZE_MAX); + if (ret) + return ERR_PTR(ret); + + node = of_unflatten_dtb(fdt); + + free(fdt); + + return node; +} + +static int do_of_diff(int argc, char *argv[]) +{ + int ret = 0; + struct device_node *a, *b, *root; + + if (argc < 3) + return COMMAND_ERROR_USAGE; + + root = of_get_root_node(); + a = get_tree(argv[1], root); + b = get_tree(argv[2], root); + + if (IS_ERR(a)) { + printf("Cannot read %s: %s\n", argv[1], strerrorp(a)); + ret = COMMAND_ERROR; + a = NULL; + goto out; + } + + if (IS_ERR(b)) { + printf("Cannot read %s: %s\n", argv[2], strerrorp(b)); + ret = COMMAND_ERROR; + b = NULL; + goto out; + } + + of_diff(a, b, 0); + + ret = 0; +out: + if (a && a != root) + of_delete_node(a); + if (b && b != root) + of_delete_node(b); + + return ret; +} + +BAREBOX_CMD_HELP_START(of_diff) +BAREBOX_CMD_HELP_TEXT("This command prints a diff between two given device trees.") +BAREBOX_CMD_HELP_TEXT("The device trees are given as dtb files or:") +BAREBOX_CMD_HELP_TEXT("'-' to compare against the barebox live tree, or") +BAREBOX_CMD_HELP_TEXT("'+' to compare against the fixed barebox live tree") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(of_diff) + .cmd = do_of_diff, + BAREBOX_CMD_DESC("diff device trees") + BAREBOX_CMD_OPTS(" ") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_of_diff_help) +BAREBOX_CMD_END -- cgit v1.2.3