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