xref: /openbmc/u-boot/tools/fdtgrep.c (revision 21299d3a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013, Google Inc.
4  * Written by Simon Glass <sjg@chromium.org>
5  *
6  * Perform a grep of an FDT either displaying the source subset or producing
7  * a new .dtb subset which can be used as required.
8  */
9 
10 #include <assert.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <getopt.h>
14 #include <fcntl.h>
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 
21 #include "fdt_host.h"
22 #include "libfdt_internal.h"
23 
24 /* Define DEBUG to get some debugging output on stderr */
25 #ifdef DEBUG
26 #define debug(a, b...) fprintf(stderr, a, ## b)
27 #else
28 #define debug(a, b...)
29 #endif
30 
31 /* A linked list of values we are grepping for */
32 struct value_node {
33 	int type;		/* Types this value matches (FDT_IS... mask) */
34 	int include;		/* 1 to include matches, 0 to exclude */
35 	const char *string;	/* String to match */
36 	struct value_node *next;	/* Pointer to next node, or NULL */
37 };
38 
39 /* Output formats we support */
40 enum output_t {
41 	OUT_DTS,		/* Device tree source */
42 	OUT_DTB,		/* Valid device tree binary */
43 	OUT_BIN,		/* Fragment of .dtb, for hashing */
44 };
45 
46 /* Holds information which controls our output and options */
47 struct display_info {
48 	enum output_t output;	/* Output format */
49 	int add_aliases;	/* Add aliases node to output */
50 	int all;		/* Display all properties/nodes */
51 	int colour;		/* Display output in ANSI colour */
52 	int region_list;	/* Output a region list */
53 	int flags;		/* Flags (FDT_REG_...) */
54 	int list_strings;	/* List strings in string table */
55 	int show_offset;	/* Show offset */
56 	int show_addr;		/* Show address */
57 	int header;		/* Output an FDT header */
58 	int diff;		/* Show +/- diff markers */
59 	int include_root;	/* Include the root node and all properties */
60 	int remove_strings;	/* Remove unused strings */
61 	int show_dts_version;	/* Put '/dts-v1/;' on the first line */
62 	int types_inc;		/* Mask of types that we include (FDT_IS...) */
63 	int types_exc;		/* Mask of types that we exclude (FDT_IS...) */
64 	int invert;		/* Invert polarity of match */
65 	struct value_node *value_head;	/* List of values to match */
66 	const char *output_fname;	/* Output filename */
67 	FILE *fout;		/* File to write dts/dtb output */
68 };
69 
70 static void report_error(const char *where, int err)
71 {
72 	fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
73 }
74 
75 /* Supported ANSI colours */
76 enum {
77 	COL_BLACK,
78 	COL_RED,
79 	COL_GREEN,
80 	COL_YELLOW,
81 	COL_BLUE,
82 	COL_MAGENTA,
83 	COL_CYAN,
84 	COL_WHITE,
85 
86 	COL_NONE = -1,
87 };
88 
89 /**
90  * print_ansi_colour() - Print out the ANSI sequence for a colour
91  *
92  * @fout:	Output file
93  * @col:	Colour to output (COL_...), or COL_NONE to reset colour
94  */
95 static void print_ansi_colour(FILE *fout, int col)
96 {
97 	if (col == COL_NONE)
98 		fprintf(fout, "\033[0m");
99 	else
100 		fprintf(fout, "\033[1;%dm", col + 30);
101 }
102 
103 
104 /**
105  * value_add() - Add a new value to our list of things to grep for
106  *
107  * @disp:	Display structure, holding info about our options
108  * @headp:	Pointer to header pointer of list
109  * @type:	Type of this value (FDT_IS_...)
110  * @include:	1 if we want to include matches, 0 to exclude
111  * @str:	String value to match
112  */
113 static int value_add(struct display_info *disp, struct value_node **headp,
114 		     int type, int include, const char *str)
115 {
116 	struct value_node *node;
117 
118 	/*
119 	 * Keep track of which types we are excluding/including. We don't
120 	 * allow both including and excluding things, because it doesn't make
121 	 * sense. 'Including' means that everything not mentioned is
122 	 * excluded. 'Excluding' means that everything not mentioned is
123 	 * included. So using the two together would be meaningless.
124 	 */
125 	if (include)
126 		disp->types_inc |= type;
127 	else
128 		disp->types_exc |= type;
129 	if (disp->types_inc & disp->types_exc & type) {
130 		fprintf(stderr,
131 			"Cannot use both include and exclude for '%s'\n", str);
132 		return -1;
133 	}
134 
135 	str = strdup(str);
136 	node = malloc(sizeof(*node));
137 	if (!str || !node) {
138 		fprintf(stderr, "Out of memory\n");
139 		return -1;
140 	}
141 	node->next = *headp;
142 	node->type = type;
143 	node->include = include;
144 	node->string = str;
145 	*headp = node;
146 
147 	return 0;
148 }
149 
150 static bool util_is_printable_string(const void *data, int len)
151 {
152 	const char *s = data;
153 	const char *ss, *se;
154 
155 	/* zero length is not */
156 	if (len == 0)
157 		return 0;
158 
159 	/* must terminate with zero */
160 	if (s[len - 1] != '\0')
161 		return 0;
162 
163 	se = s + len;
164 
165 	while (s < se) {
166 		ss = s;
167 		while (s < se && *s && isprint((unsigned char)*s))
168 			s++;
169 
170 		/* not zero, or not done yet */
171 		if (*s != '\0' || s == ss)
172 			return 0;
173 
174 		s++;
175 	}
176 
177 	return 1;
178 }
179 
180 static void utilfdt_print_data(const char *data, int len)
181 {
182 	int i;
183 	const char *p = data;
184 	const char *s;
185 
186 	/* no data, don't print */
187 	if (len == 0)
188 		return;
189 
190 	if (util_is_printable_string(data, len)) {
191 		printf(" = ");
192 
193 		s = data;
194 		do {
195 			printf("\"%s\"", s);
196 			s += strlen(s) + 1;
197 			if (s < data + len)
198 				printf(", ");
199 		} while (s < data + len);
200 
201 	} else if ((len % 4) == 0) {
202 		const uint32_t *cell = (const uint32_t *)data;
203 
204 		printf(" = <");
205 		for (i = 0, len /= 4; i < len; i++)
206 			printf("0x%08x%s", fdt32_to_cpu(cell[i]),
207 			       i < (len - 1) ? " " : "");
208 		printf(">");
209 	} else {
210 		printf(" = [");
211 		for (i = 0; i < len; i++)
212 			printf("%02x%s", *p++, i < len - 1 ? " " : "");
213 		printf("]");
214 	}
215 }
216 
217 /**
218  * display_fdt_by_regions() - Display regions of an FDT source
219  *
220  * This dumps an FDT as source, but only certain regions of it. This is the
221  * final stage of the grep - we have a list of regions we want to display,
222  * and this function displays them.
223  *
224  * @disp:	Display structure, holding info about our options
225  * @blob:	FDT blob to display
226  * @region:	List of regions to display
227  * @count:	Number of regions
228  */
229 static int display_fdt_by_regions(struct display_info *disp, const void *blob,
230 		struct fdt_region region[], int count)
231 {
232 	struct fdt_region *reg = region, *reg_end = region + count;
233 	uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
234 	int base = fdt_off_dt_struct(blob);
235 	int version = fdt_version(blob);
236 	int offset, nextoffset;
237 	int tag, depth, shift;
238 	FILE *f = disp->fout;
239 	uint64_t addr, size;
240 	int in_region;
241 	int file_ofs;
242 	int i;
243 
244 	if (disp->show_dts_version)
245 		fprintf(f, "/dts-v1/;\n");
246 
247 	if (disp->header) {
248 		fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
249 		fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
250 			fdt_totalsize(blob));
251 		fprintf(f, "// off_dt_struct:\t0x%x\n",
252 			fdt_off_dt_struct(blob));
253 		fprintf(f, "// off_dt_strings:\t0x%x\n",
254 			fdt_off_dt_strings(blob));
255 		fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
256 		fprintf(f, "// version:\t\t%d\n", version);
257 		fprintf(f, "// last_comp_version:\t%d\n",
258 			fdt_last_comp_version(blob));
259 		if (version >= 2) {
260 			fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
261 				fdt_boot_cpuid_phys(blob));
262 		}
263 		if (version >= 3) {
264 			fprintf(f, "// size_dt_strings:\t0x%x\n",
265 				fdt_size_dt_strings(blob));
266 		}
267 		if (version >= 17) {
268 			fprintf(f, "// size_dt_struct:\t0x%x\n",
269 				fdt_size_dt_struct(blob));
270 		}
271 		fprintf(f, "\n");
272 	}
273 
274 	if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
275 		const struct fdt_reserve_entry *p_rsvmap;
276 
277 		p_rsvmap = (const struct fdt_reserve_entry *)
278 				((const char *)blob + off_mem_rsvmap);
279 		for (i = 0; ; i++) {
280 			addr = fdt64_to_cpu(p_rsvmap[i].address);
281 			size = fdt64_to_cpu(p_rsvmap[i].size);
282 			if (addr == 0 && size == 0)
283 				break;
284 
285 			fprintf(f, "/memreserve/ %llx %llx;\n",
286 				(unsigned long long)addr,
287 				(unsigned long long)size);
288 		}
289 	}
290 
291 	depth = 0;
292 	nextoffset = 0;
293 	shift = 4;	/* 4 spaces per indent */
294 	do {
295 		const struct fdt_property *prop;
296 		const char *name;
297 		int show;
298 		int len;
299 
300 		offset = nextoffset;
301 
302 		/*
303 		 * Work out the file offset of this offset, and decide
304 		 * whether it is in the region list or not
305 		 */
306 		file_ofs = base + offset;
307 		if (reg < reg_end && file_ofs >= reg->offset + reg->size)
308 			reg++;
309 		in_region = reg < reg_end && file_ofs >= reg->offset &&
310 				file_ofs < reg->offset + reg->size;
311 		tag = fdt_next_tag(blob, offset, &nextoffset);
312 
313 		if (tag == FDT_END)
314 			break;
315 		show = in_region || disp->all;
316 		if (show && disp->diff)
317 			fprintf(f, "%c", in_region ? '+' : '-');
318 
319 		if (!show) {
320 			/* Do this here to avoid 'if (show)' in every 'case' */
321 			if (tag == FDT_BEGIN_NODE)
322 				depth++;
323 			else if (tag == FDT_END_NODE)
324 				depth--;
325 			continue;
326 		}
327 		if (tag != FDT_END) {
328 			if (disp->show_addr)
329 				fprintf(f, "%4x: ", file_ofs);
330 			if (disp->show_offset)
331 				fprintf(f, "%4x: ", file_ofs - base);
332 		}
333 
334 		/* Green means included, red means excluded */
335 		if (disp->colour)
336 			print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
337 
338 		switch (tag) {
339 		case FDT_PROP:
340 			prop = fdt_get_property_by_offset(blob, offset, NULL);
341 			name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
342 			fprintf(f, "%*s%s", depth * shift, "", name);
343 			utilfdt_print_data(prop->data,
344 					   fdt32_to_cpu(prop->len));
345 			fprintf(f, ";");
346 			break;
347 
348 		case FDT_NOP:
349 			fprintf(f, "%*s// [NOP]", depth * shift, "");
350 			break;
351 
352 		case FDT_BEGIN_NODE:
353 			name = fdt_get_name(blob, offset, &len);
354 			fprintf(f, "%*s%s {", depth++ * shift, "",
355 				*name ? name : "/");
356 			break;
357 
358 		case FDT_END_NODE:
359 			fprintf(f, "%*s};", --depth * shift, "");
360 			break;
361 		}
362 
363 		/* Reset colour back to normal before end of line */
364 		if (disp->colour)
365 			print_ansi_colour(f, COL_NONE);
366 		fprintf(f, "\n");
367 	} while (1);
368 
369 	/* Print a list of strings if requested */
370 	if (disp->list_strings) {
371 		const char *str;
372 		int str_base = fdt_off_dt_strings(blob);
373 
374 		for (offset = 0; offset < fdt_size_dt_strings(blob);
375 				offset += strlen(str) + 1) {
376 			str = fdt_string(blob, offset);
377 			int len = strlen(str) + 1;
378 			int show;
379 
380 			/* Only print strings that are in the region */
381 			file_ofs = str_base + offset;
382 			in_region = reg < reg_end &&
383 					file_ofs >= reg->offset &&
384 					file_ofs + len < reg->offset +
385 						reg->size;
386 			show = in_region || disp->all;
387 			if (show && disp->diff)
388 				printf("%c", in_region ? '+' : '-');
389 			if (disp->show_addr)
390 				printf("%4x: ", file_ofs);
391 			if (disp->show_offset)
392 				printf("%4x: ", offset);
393 			printf("%s\n", str);
394 		}
395 	}
396 
397 	return 0;
398 }
399 
400 /**
401  * dump_fdt_regions() - Dump regions of an FDT as binary data
402  *
403  * This dumps an FDT as binary, but only certain regions of it. This is the
404  * final stage of the grep - we have a list of regions we want to dump,
405  * and this function dumps them.
406  *
407  * The output of this function may or may not be a valid FDT. To ensure it
408  * is, these disp->flags must be set:
409  *
410  *   FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
411  *		parents. Without this option, fragments of subnode data may be
412  *		output without the supernodes above them. This is useful for
413  *		hashing but cannot produce a valid FDT.
414  *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
415  *		Without this none of the properties will have names
416  *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
417  *		without this.
418  *
419  * @disp:	Display structure, holding info about our options
420  * @blob:	FDT blob to display
421  * @region:	List of regions to display
422  * @count:	Number of regions
423  * @out:	Output destination
424  */
425 static int dump_fdt_regions(struct display_info *disp, const void *blob,
426 		struct fdt_region region[], int count, char *out)
427 {
428 	struct fdt_header *fdt;
429 	int size, struct_start;
430 	int ptr;
431 	int i;
432 
433 	/* Set up a basic header (even if we don't actually write it) */
434 	fdt = (struct fdt_header *)out;
435 	memset(fdt, '\0', sizeof(*fdt));
436 	fdt_set_magic(fdt, FDT_MAGIC);
437 	struct_start = FDT_ALIGN(sizeof(struct fdt_header),
438 					sizeof(struct fdt_reserve_entry));
439 	fdt_set_off_mem_rsvmap(fdt, struct_start);
440 	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
441 	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
442 
443 	/*
444 	 * Calculate the total size of the regions we are writing out. The
445 	 * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
446 	 * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
447 	 * is set.
448 	 */
449 	for (i = size = 0; i < count; i++)
450 		size += region[i].size;
451 
452 	/* Bring in the mem_rsvmap section from the old file if requested */
453 	if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
454 		struct_start += region[0].size;
455 		size -= region[0].size;
456 	}
457 	fdt_set_off_dt_struct(fdt, struct_start);
458 
459 	/* Update the header to have the correct offsets/sizes */
460 	if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
461 		int str_size;
462 
463 		str_size = region[count - 1].size;
464 		fdt_set_size_dt_struct(fdt, size - str_size);
465 		fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
466 		fdt_set_size_dt_strings(fdt, str_size);
467 		fdt_set_totalsize(fdt, struct_start + size);
468 	}
469 
470 	/* Write the header if required */
471 	ptr = 0;
472 	if (disp->header) {
473 		ptr = sizeof(*fdt);
474 		while (ptr < fdt_off_mem_rsvmap(fdt))
475 			out[ptr++] = '\0';
476 	}
477 
478 	/* Output all the nodes including any mem_rsvmap/string table */
479 	for (i = 0; i < count; i++) {
480 		struct fdt_region *reg = &region[i];
481 
482 		memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
483 		ptr += reg->size;
484 	}
485 
486 	return ptr;
487 }
488 
489 /**
490  * show_region_list() - Print out a list of regions
491  *
492  * The list includes the region offset (absolute offset from start of FDT
493  * blob in bytes) and size
494  *
495  * @reg:	List of regions to print
496  * @count:	Number of regions
497  */
498 static void show_region_list(struct fdt_region *reg, int count)
499 {
500 	int i;
501 
502 	printf("Regions: %d\n", count);
503 	for (i = 0; i < count; i++, reg++) {
504 		printf("%d:  %-10x  %-10x\n", i, reg->offset,
505 		       reg->offset + reg->size);
506 	}
507 }
508 
509 static int check_type_include(void *priv, int type, const char *data, int size)
510 {
511 	struct display_info *disp = priv;
512 	struct value_node *val;
513 	int match, none_match = FDT_IS_ANY;
514 
515 	/* If none of our conditions mention this type, we know nothing */
516 	debug("type=%x, data=%s\n", type, data ? data : "(null)");
517 	if (!((disp->types_inc | disp->types_exc) & type)) {
518 		debug("   - not in any condition\n");
519 		return -1;
520 	}
521 
522 	/*
523 	 * Go through the list of conditions. For inclusive conditions, we
524 	 * return 1 at the first match. For exclusive conditions, we must
525 	 * check that there are no matches.
526 	 */
527 	if (data) {
528 		for (val = disp->value_head; val; val = val->next) {
529 			if (!(type & val->type))
530 				continue;
531 			match = fdt_stringlist_contains(data, size,
532 							val->string);
533 			debug("      - val->type=%x, str='%s', match=%d\n",
534 			      val->type, val->string, match);
535 			if (match && val->include) {
536 				debug("   - match inc %s\n", val->string);
537 				return 1;
538 			}
539 			if (match)
540 				none_match &= ~val->type;
541 		}
542 	}
543 
544 	/*
545 	 * If this is an exclusive condition, and nothing matches, then we
546 	 * should return 1.
547 	 */
548 	if ((type & disp->types_exc) && (none_match & type)) {
549 		debug("   - match exc\n");
550 		/*
551 		 * Allow FDT_IS_COMPAT to make the final decision in the
552 		 * case where there is no specific type
553 		 */
554 		if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
555 			debug("   - supressed exc node\n");
556 			return -1;
557 		}
558 		return 1;
559 	}
560 
561 	/*
562 	 * Allow FDT_IS_COMPAT to make the final decision in the
563 	 * case where there is no specific type (inclusive)
564 	 */
565 	if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
566 		return -1;
567 
568 	debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
569 	      disp->types_inc, disp->types_exc, none_match);
570 
571 	return 0;
572 }
573 
574 /**
575  * h_include() - Include handler function for fdt_find_regions()
576  *
577  * This function decides whether to include or exclude a node, property or
578  * compatible string. The function is defined by fdt_find_regions().
579  *
580  * The algorithm is documented in the code - disp->invert is 0 for normal
581  * operation, and 1 to invert the sense of all matches.
582  *
583  * See
584  */
585 static int h_include(void *priv, const void *fdt, int offset, int type,
586 		     const char *data, int size)
587 {
588 	struct display_info *disp = priv;
589 	int inc, len;
590 
591 	inc = check_type_include(priv, type, data, size);
592 	if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
593 		return 1;
594 
595 	/*
596 	 * If the node name does not tell us anything, check the
597 	 * compatible string
598 	 */
599 	if (inc == -1 && type == FDT_IS_NODE) {
600 		debug("   - checking compatible2\n");
601 		data = fdt_getprop(fdt, offset, "compatible", &len);
602 		inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
603 	}
604 
605 	/* If we still have no idea, check for properties in the node */
606 	if (inc != 1 && type == FDT_IS_NODE &&
607 	    (disp->types_inc & FDT_NODE_HAS_PROP)) {
608 		debug("   - checking node '%s'\n",
609 		      fdt_get_name(fdt, offset, NULL));
610 		for (offset = fdt_first_property_offset(fdt, offset);
611 		     offset > 0 && inc != 1;
612 		     offset = fdt_next_property_offset(fdt, offset)) {
613 			const struct fdt_property *prop;
614 			const char *str;
615 
616 			prop = fdt_get_property_by_offset(fdt, offset, NULL);
617 			if (!prop)
618 				continue;
619 			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
620 			inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
621 						 strlen(str));
622 		}
623 		if (inc == -1)
624 			inc = 0;
625 	}
626 
627 	switch (inc) {
628 	case 1:
629 		inc = !disp->invert;
630 		break;
631 	case 0:
632 		inc = disp->invert;
633 		break;
634 	}
635 	debug("   - returning %d\n", inc);
636 
637 	return inc;
638 }
639 
640 static int h_cmp_region(const void *v1, const void *v2)
641 {
642 	const struct fdt_region *region1 = v1, *region2 = v2;
643 
644 	return region1->offset - region2->offset;
645 }
646 
647 static int fdtgrep_find_regions(const void *fdt,
648 		int (*include_func)(void *priv, const void *fdt, int offset,
649 				 int type, const char *data, int size),
650 		struct display_info *disp, struct fdt_region *region,
651 		int max_regions, char *path, int path_len, int flags)
652 {
653 	struct fdt_region_state state;
654 	int count;
655 	int ret;
656 
657 	count = 0;
658 	ret = fdt_first_region(fdt, include_func, disp,
659 			&region[count++], path, path_len,
660 			disp->flags, &state);
661 	while (ret == 0) {
662 		ret = fdt_next_region(fdt, include_func, disp,
663 				count < max_regions ? &region[count] : NULL,
664 				path, path_len, disp->flags, &state);
665 		if (!ret)
666 			count++;
667 	}
668 	if (ret && ret != -FDT_ERR_NOTFOUND)
669 		return ret;
670 
671 	/* Find all the aliases and add those regions back in */
672 	if (disp->add_aliases && count < max_regions) {
673 		int new_count;
674 
675 		new_count = fdt_add_alias_regions(fdt, region, count,
676 						  max_regions, &state);
677 		if (new_count == -FDT_ERR_NOTFOUND) {
678 			/* No alias node found */
679 		} else if (new_count < 0) {
680 			return new_count;
681 		} else if (new_count <= max_regions) {
682 			/*
683 			* The alias regions will now be at the end of the list.
684 			* Sort the regions by offset to get things into the
685 			* right order
686 			*/
687 			count = new_count;
688 			qsort(region, count, sizeof(struct fdt_region),
689 			      h_cmp_region);
690 		}
691 	}
692 
693 	return count;
694 }
695 
696 int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
697 {
698 	int fd = 0;	/* assume stdin */
699 	char *buf = NULL;
700 	off_t bufsize = 1024, offset = 0;
701 	int ret = 0;
702 
703 	*buffp = NULL;
704 	if (strcmp(filename, "-") != 0) {
705 		fd = open(filename, O_RDONLY);
706 		if (fd < 0)
707 			return errno;
708 	}
709 
710 	/* Loop until we have read everything */
711 	buf = malloc(bufsize);
712 	if (!buf)
713 		return -ENOMEM;
714 	do {
715 		/* Expand the buffer to hold the next chunk */
716 		if (offset == bufsize) {
717 			bufsize *= 2;
718 			buf = realloc(buf, bufsize);
719 			if (!buf)
720 				return -ENOMEM;
721 		}
722 
723 		ret = read(fd, &buf[offset], bufsize - offset);
724 		if (ret < 0) {
725 			ret = errno;
726 			break;
727 		}
728 		offset += ret;
729 	} while (ret != 0);
730 
731 	/* Clean up, including closing stdin; return errno on error */
732 	close(fd);
733 	if (ret)
734 		free(buf);
735 	else
736 		*buffp = buf;
737 	*len = bufsize;
738 	return ret;
739 }
740 
741 int utilfdt_read_err(const char *filename, char **buffp)
742 {
743 	off_t len;
744 	return utilfdt_read_err_len(filename, buffp, &len);
745 }
746 
747 char *utilfdt_read_len(const char *filename, off_t *len)
748 {
749 	char *buff;
750 	int ret = utilfdt_read_err_len(filename, &buff, len);
751 
752 	if (ret) {
753 		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
754 			strerror(ret));
755 		return NULL;
756 	}
757 	/* Successful read */
758 	return buff;
759 }
760 
761 char *utilfdt_read(const char *filename)
762 {
763 	off_t len;
764 	return utilfdt_read_len(filename, &len);
765 }
766 
767 /**
768  * Run the main fdtgrep operation, given a filename and valid arguments
769  *
770  * @param disp		Display information / options
771  * @param filename	Filename of blob file
772  * @param return 0 if ok, -ve on error
773  */
774 static int do_fdtgrep(struct display_info *disp, const char *filename)
775 {
776 	struct fdt_region *region;
777 	int max_regions;
778 	int count = 100;
779 	char path[1024];
780 	char *blob;
781 	int i, ret;
782 
783 	blob = utilfdt_read(filename);
784 	if (!blob)
785 		return -1;
786 	ret = fdt_check_header(blob);
787 	if (ret) {
788 		fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
789 		return ret;
790 	}
791 
792 	/* Allow old files, but they are untested */
793 	if (fdt_version(blob) < 17 && disp->value_head) {
794 		fprintf(stderr,
795 			"Warning: fdtgrep does not fully support version %d files\n",
796 			fdt_version(blob));
797 	}
798 
799 	/*
800 	 * We do two passes, since we don't know how many regions we need.
801 	 * The first pass will count the regions, but if it is too many,
802 	 * we do another pass to actually record them.
803 	 */
804 	for (i = 0; i < 3; i++) {
805 		region = malloc(count * sizeof(struct fdt_region));
806 		if (!region) {
807 			fprintf(stderr, "Out of memory for %d regions\n",
808 				count);
809 			return -1;
810 		}
811 		max_regions = count;
812 		count = fdtgrep_find_regions(blob,
813 				h_include, disp,
814 				region, max_regions, path, sizeof(path),
815 				disp->flags);
816 		if (count < 0) {
817 			report_error("fdt_find_regions", count);
818 			return -1;
819 		}
820 		if (count <= max_regions)
821 			break;
822 		free(region);
823 	}
824 
825 	/* Optionally print a list of regions */
826 	if (disp->region_list)
827 		show_region_list(region, count);
828 
829 	/* Output either source .dts or binary .dtb */
830 	if (disp->output == OUT_DTS) {
831 		ret = display_fdt_by_regions(disp, blob, region, count);
832 	} else {
833 		void *fdt;
834 		/* Allow reserved memory section to expand slightly */
835 		int size = fdt_totalsize(blob) + 16;
836 
837 		fdt = malloc(size);
838 		if (!fdt) {
839 			fprintf(stderr, "Out_of_memory\n");
840 			ret = -1;
841 			goto err;
842 		}
843 		size = dump_fdt_regions(disp, blob, region, count, fdt);
844 		if (disp->remove_strings) {
845 			void *out;
846 
847 			out = malloc(size);
848 			if (!out) {
849 				fprintf(stderr, "Out_of_memory\n");
850 				ret = -1;
851 				goto err;
852 			}
853 			ret = fdt_remove_unused_strings(fdt, out);
854 			if (ret < 0) {
855 				fprintf(stderr,
856 					"Failed to remove unused strings: err=%d\n",
857 					ret);
858 				goto err;
859 			}
860 			free(fdt);
861 			fdt = out;
862 			ret = fdt_pack(fdt);
863 			if (ret < 0) {
864 				fprintf(stderr, "Failed to pack: err=%d\n",
865 					ret);
866 				goto err;
867 			}
868 			size = fdt_totalsize(fdt);
869 		}
870 
871 		if (size != fwrite(fdt, 1, size, disp->fout)) {
872 			fprintf(stderr, "Write failure, %d bytes\n", size);
873 			free(fdt);
874 			ret = 1;
875 			goto err;
876 		}
877 		free(fdt);
878 	}
879 err:
880 	free(blob);
881 	free(region);
882 
883 	return ret;
884 }
885 
886 static const char usage_synopsis[] =
887 	"fdtgrep - extract portions from device tree\n"
888 	"\n"
889 	"Usage:\n"
890 	"	fdtgrep <options> <dt file>|-\n\n"
891 	"Output formats are:\n"
892 	"\tdts - device tree soure text\n"
893 	"\tdtb - device tree blob (sets -Hmt automatically)\n"
894 	"\tbin - device tree fragment (may not be a valid .dtb)";
895 
896 /* Helper for usage_short_opts string constant */
897 #define USAGE_COMMON_SHORT_OPTS "hV"
898 
899 /* Helper for aligning long_opts array */
900 #define a_argument required_argument
901 
902 /* Helper for usage_long_opts option array */
903 #define USAGE_COMMON_LONG_OPTS \
904 	{"help",      no_argument, NULL, 'h'}, \
905 	{"version",   no_argument, NULL, 'V'}, \
906 	{NULL,        no_argument, NULL, 0x0}
907 
908 /* Helper for usage_opts_help array */
909 #define USAGE_COMMON_OPTS_HELP \
910 	"Print this help and exit", \
911 	"Print version and exit", \
912 	NULL
913 
914 /* Helper for getopt case statements */
915 #define case_USAGE_COMMON_FLAGS \
916 	case 'h': usage(NULL); \
917 	case 'V': util_version(); \
918 	case '?': usage("unknown option");
919 
920 static const char usage_short_opts[] =
921 		"haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
922 		USAGE_COMMON_SHORT_OPTS;
923 static struct option const usage_long_opts[] = {
924 	{"show-address",	no_argument, NULL, 'a'},
925 	{"colour",		no_argument, NULL, 'A'},
926 	{"include-node-with-prop", a_argument, NULL, 'b'},
927 	{"include-compat",	a_argument, NULL, 'c'},
928 	{"exclude-compat",	a_argument, NULL, 'C'},
929 	{"diff",		no_argument, NULL, 'd'},
930 	{"enter-node",		no_argument, NULL, 'e'},
931 	{"show-offset",		no_argument, NULL, 'f'},
932 	{"include-match",	a_argument, NULL, 'g'},
933 	{"exclude-match",	a_argument, NULL, 'G'},
934 	{"show-header",		no_argument, NULL, 'H'},
935 	{"show-version",	no_argument, NULL, 'I'},
936 	{"list-regions",	no_argument, NULL, 'l'},
937 	{"list-strings",	no_argument, NULL, 'L'},
938 	{"include-mem",		no_argument, NULL, 'm'},
939 	{"include-node",	a_argument, NULL, 'n'},
940 	{"exclude-node",	a_argument, NULL, 'N'},
941 	{"include-prop",	a_argument, NULL, 'p'},
942 	{"exclude-prop",	a_argument, NULL, 'P'},
943 	{"remove-strings",	no_argument, NULL, 'r'},
944 	{"include-root",	no_argument, NULL, 'R'},
945 	{"show-subnodes",	no_argument, NULL, 's'},
946 	{"skip-supernodes",	no_argument, NULL, 'S'},
947 	{"show-stringtab",	no_argument, NULL, 't'},
948 	{"show-aliases",	no_argument, NULL, 'T'},
949 	{"out",			a_argument, NULL, 'o'},
950 	{"out-format",		a_argument, NULL, 'O'},
951 	{"invert-match",	no_argument, NULL, 'v'},
952 	USAGE_COMMON_LONG_OPTS,
953 };
954 static const char * const usage_opts_help[] = {
955 	"Display address",
956 	"Show all nodes/tags, colour those that match",
957 	"Include contains containing property",
958 	"Compatible nodes to include in grep",
959 	"Compatible nodes to exclude in grep",
960 	"Diff: Mark matching nodes with +, others with -",
961 	"Enter direct subnode names of matching nodes",
962 	"Display offset",
963 	"Node/property/compatible string to include in grep",
964 	"Node/property/compatible string to exclude in grep",
965 	"Output a header",
966 	"Put \"/dts-v1/;\" on first line of dts output",
967 	"Output a region list",
968 	"List strings in string table",
969 	"Include mem_rsvmap section in binary output",
970 	"Node to include in grep",
971 	"Node to exclude in grep",
972 	"Property to include in grep",
973 	"Property to exclude in grep",
974 	"Remove unused strings from string table",
975 	"Include root node and all properties",
976 	"Show all subnodes matching nodes",
977 	"Don't include supernodes of matching nodes",
978 	"Include string table in binary output",
979 	"Include matching aliases in output",
980 	"-o <output file>",
981 	"-O <output format>",
982 	"Invert the sense of matching (select non-matching lines)",
983 	USAGE_COMMON_OPTS_HELP
984 };
985 
986 /**
987  * Call getopt_long() with standard options
988  *
989  * Since all util code runs getopt in the same way, provide a helper.
990  */
991 #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
992 				       usage_long_opts, NULL)
993 
994 void util_usage(const char *errmsg, const char *synopsis,
995 		const char *short_opts, struct option const long_opts[],
996 		const char * const opts_help[])
997 {
998 	FILE *fp = errmsg ? stderr : stdout;
999 	const char a_arg[] = "<arg>";
1000 	size_t a_arg_len = strlen(a_arg) + 1;
1001 	size_t i;
1002 	int optlen;
1003 
1004 	fprintf(fp,
1005 		"Usage: %s\n"
1006 		"\n"
1007 		"Options: -[%s]\n", synopsis, short_opts);
1008 
1009 	/* prescan the --long opt length to auto-align */
1010 	optlen = 0;
1011 	for (i = 0; long_opts[i].name; ++i) {
1012 		/* +1 is for space between --opt and help text */
1013 		int l = strlen(long_opts[i].name) + 1;
1014 		if (long_opts[i].has_arg == a_argument)
1015 			l += a_arg_len;
1016 		if (optlen < l)
1017 			optlen = l;
1018 	}
1019 
1020 	for (i = 0; long_opts[i].name; ++i) {
1021 		/* helps when adding new applets or options */
1022 		assert(opts_help[i] != NULL);
1023 
1024 		/* first output the short flag if it has one */
1025 		if (long_opts[i].val > '~')
1026 			fprintf(fp, "      ");
1027 		else
1028 			fprintf(fp, "  -%c, ", long_opts[i].val);
1029 
1030 		/* then the long flag */
1031 		if (long_opts[i].has_arg == no_argument) {
1032 			fprintf(fp, "--%-*s", optlen, long_opts[i].name);
1033 		} else {
1034 			fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
1035 				(int)(optlen - strlen(long_opts[i].name) -
1036 				a_arg_len), "");
1037 		}
1038 
1039 		/* finally the help text */
1040 		fprintf(fp, "%s\n", opts_help[i]);
1041 	}
1042 
1043 	if (errmsg) {
1044 		fprintf(fp, "\nError: %s\n", errmsg);
1045 		exit(EXIT_FAILURE);
1046 	} else {
1047 		exit(EXIT_SUCCESS);
1048 	}
1049 }
1050 
1051 /**
1052  * Show usage and exit
1053  *
1054  * If you name all your usage variables with usage_xxx, then you can call this
1055  * help macro rather than expanding all arguments yourself.
1056  *
1057  * @param errmsg	If non-NULL, an error message to display
1058  */
1059 #define usage(errmsg) \
1060 	util_usage(errmsg, usage_synopsis, usage_short_opts, \
1061 		   usage_long_opts, usage_opts_help)
1062 
1063 void util_version(void)
1064 {
1065 	printf("Version: %s\n", "(U-Boot)");
1066 	exit(0);
1067 }
1068 
1069 static void scan_args(struct display_info *disp, int argc, char *argv[])
1070 {
1071 	int opt;
1072 
1073 	while ((opt = util_getopt_long()) != EOF) {
1074 		int type = 0;
1075 		int inc = 1;
1076 
1077 		switch (opt) {
1078 		case_USAGE_COMMON_FLAGS
1079 		case 'a':
1080 			disp->show_addr = 1;
1081 			break;
1082 		case 'A':
1083 			disp->all = 1;
1084 			break;
1085 		case 'b':
1086 			type = FDT_NODE_HAS_PROP;
1087 			break;
1088 		case 'C':
1089 			inc = 0;
1090 			/* no break */
1091 		case 'c':
1092 			type = FDT_IS_COMPAT;
1093 			break;
1094 		case 'd':
1095 			disp->diff = 1;
1096 			break;
1097 		case 'e':
1098 			disp->flags |= FDT_REG_DIRECT_SUBNODES;
1099 			break;
1100 		case 'f':
1101 			disp->show_offset = 1;
1102 			break;
1103 		case 'G':
1104 			inc = 0;
1105 			/* no break */
1106 		case 'g':
1107 			type = FDT_ANY_GLOBAL;
1108 			break;
1109 		case 'H':
1110 			disp->header = 1;
1111 			break;
1112 		case 'l':
1113 			disp->region_list = 1;
1114 			break;
1115 		case 'L':
1116 			disp->list_strings = 1;
1117 			break;
1118 		case 'm':
1119 			disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
1120 			break;
1121 		case 'N':
1122 			inc = 0;
1123 			/* no break */
1124 		case 'n':
1125 			type = FDT_IS_NODE;
1126 			break;
1127 		case 'o':
1128 			disp->output_fname = optarg;
1129 			break;
1130 		case 'O':
1131 			if (!strcmp(optarg, "dtb"))
1132 				disp->output = OUT_DTB;
1133 			else if (!strcmp(optarg, "dts"))
1134 				disp->output = OUT_DTS;
1135 			else if (!strcmp(optarg, "bin"))
1136 				disp->output = OUT_BIN;
1137 			else
1138 				usage("Unknown output format");
1139 			break;
1140 		case 'P':
1141 			inc = 0;
1142 			/* no break */
1143 		case 'p':
1144 			type = FDT_IS_PROP;
1145 			break;
1146 		case 'r':
1147 			disp->remove_strings = 1;
1148 			break;
1149 		case 'R':
1150 			disp->include_root = 1;
1151 			break;
1152 		case 's':
1153 			disp->flags |= FDT_REG_ALL_SUBNODES;
1154 			break;
1155 		case 'S':
1156 			disp->flags &= ~FDT_REG_SUPERNODES;
1157 			break;
1158 		case 't':
1159 			disp->flags |= FDT_REG_ADD_STRING_TAB;
1160 			break;
1161 		case 'T':
1162 			disp->add_aliases = 1;
1163 			break;
1164 		case 'v':
1165 			disp->invert = 1;
1166 			break;
1167 		case 'I':
1168 			disp->show_dts_version = 1;
1169 			break;
1170 		}
1171 
1172 		if (type && value_add(disp, &disp->value_head, type, inc,
1173 				      optarg))
1174 			usage("Cannot add value");
1175 	}
1176 
1177 	if (disp->invert && disp->types_exc)
1178 		usage("-v has no meaning when used with 'exclude' conditions");
1179 }
1180 
1181 int main(int argc, char *argv[])
1182 {
1183 	char *filename = NULL;
1184 	struct display_info disp;
1185 	int ret;
1186 
1187 	/* set defaults */
1188 	memset(&disp, '\0', sizeof(disp));
1189 	disp.flags = FDT_REG_SUPERNODES;	/* Default flags */
1190 
1191 	scan_args(&disp, argc, argv);
1192 
1193 	/* Show matched lines in colour if we can */
1194 	disp.colour = disp.all && isatty(0);
1195 
1196 	/* Any additional arguments can match anything, just like -g */
1197 	while (optind < argc - 1) {
1198 		if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
1199 			      argv[optind++]))
1200 			usage("Cannot add value");
1201 	}
1202 
1203 	if (optind < argc)
1204 		filename = argv[optind++];
1205 	if (!filename)
1206 		usage("Missing filename");
1207 
1208 	/* If a valid .dtb is required, set flags to ensure we get one */
1209 	if (disp.output == OUT_DTB) {
1210 		disp.header = 1;
1211 		disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
1212 	}
1213 
1214 	if (disp.output_fname) {
1215 		disp.fout = fopen(disp.output_fname, "w");
1216 		if (!disp.fout)
1217 			usage("Cannot open output file");
1218 	} else {
1219 		disp.fout = stdout;
1220 	}
1221 
1222 	/* Run the grep and output the results */
1223 	ret = do_fdtgrep(&disp, filename);
1224 	if (disp.output_fname)
1225 		fclose(disp.fout);
1226 	if (ret)
1227 		return 1;
1228 
1229 	return 0;
1230 }
1231