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