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